8 solutions

  • 2
    @ 2021-10-17 18:00:10

    P1037. 中国身份证号码校验

    了解到一部分同学不懂ASCII码,于 10.20 更新一份ASCII码说明

    题意概述

    省份证号码存在一位校验码,这位校验码是使用号码的前17位数字通过数乘、求和后取余11得到数字又会去对应一个数,这个数就是校验码。

    题意分析

    这里,我第一眼想到的解决方案是使用打表(或许这就是蒟蒻的特点吧!),我打了几个后....算了,为了偷懒换了一个打表方式,将需要数乘和结果对应的数列放到数组里面。(简单提一下,不会有人用long long来存储省份证号吧!应为省份证号中有X,我们就不使用int型变量,用字符数组存储)。

    比如,:7-9-10-5-8-4-2-1-6-3-7-9-10-5-8-4-2,就可以建立一个数组存储,然后根据循环时角标一一对应即可。另外的数列同理。

    这里说一下我怎么处理X的,在后面做特判也是可以的,我是直接把X换成('9'+1)这样子可以省点代码。

    可行代码

    #include <iostream>
    using namespace std;
    int main(){
        int T;
        cin >> T;
        while(T--){
            char num[20];
            cin >> num;
            if(num[17] == 'X') 
                num[17] = '9' + 1;
            int cs[] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
            int res[] = {1,0,10,9,8,7,6,5,4,3,2};
            int sum = 0;
            for(int i = 0; i < 17; i++){
                sum += (num[i] - '0') * cs[i];
            }
            sum %= 11;
            if(res[sum] + '0' == num[17])
                cout << "True" << endl;
            else 
                cout << "False" << endl;
        }
        return 0;
    }
    

    EDN 看到这个题AC率一路下滑,就来发一篇题解,看不懂的私聊我。AC每一天!

    ASCII

    美国信息交换标准代码(American Standard Code for Information Interchange)

    简单引入

    如果只是想简单了解使用的话,直接跳转到 ASCII码的特点

    众所周知,计算机硬件决定了计算机它只懂二进制,也就是计算机内实际上所有的东西都是(0/1)组成。包括我们的字符也是这样子,那么这些字符在计算机内如何表示呢?C语言是一门开放的语言,在这里面字符仅仅是字符吗?希望你看到这里带着这两个问题去思考。

    认识char

    大家都学习了char这种数据类型,我们都知道它可以存储字符。但是,其内部结构如何呢?

    我们来浅显的(知识有限只能浅显)分析一下:

    计算机内只能存储(0/1),之前我们也学到char是一个字节(1B),也就是说char数据类型有1B的空间。在1B的空间内可以存储8个位,每个位有两种状态也就是(0/1)。

    那么我们是否可以建立一套规则来用8个位的不同状态来表达不同的字符呢?是的,字符编码规则就和这差不多。

    ASICC码规定字符 '0' 的码为下面这一串 01 串: '0'的内部结构

    根据不同的01串表达方式不同状态表达不同字符,利用与 '0' 相同的方法建立一套字符表达体系:

    ASCII 可以看到每个字符会对应一个十进制整数,那就是它的编码。

    我们来算一笔帐,表中所给出的字符应该是有 128 个吧!但是我们上文提到, char 有八个位应该可以表达 256 种情况,其实最高位和 int 有异曲同工之妙,都是符号位!

    这里也可以看出, char 和 int 是相通的。我们不妨对 char 的 01 串用二进制的方式来算一算:

    正好是(2^5 × 1) + (2^4 × 1) + (2^3 × 0) + 0 + 0 + 0 = 48

    所以实际上我们可以将 char 也视作是数字,但是比较特殊。当你使用 %d 输出发现是整数,用 %c 输出发现是字符,其实就是看你在不同情况下如何看待这一个01串。

    char ch = '0';
    printf("%d\n", ch); // 输出 48
    printf("%c\n", ch); // 输出 0
    

    ASCII码的特点

    可以看到这里面有很多不认识的字符,一些熟悉的字符。前面一大部分字符都是都是没有具体表达形式,但是,它们具有自己的功能。除了需要了解 NULL 的 ASCII 码为 0 外,前面没太多需要注意(只针对在我们这些竞赛领域)。大部分的字符都是不需要记住的,一般来说,知道 '0' 是 48 就很好推出每一个数字的值,但是大多数时候我们直接使用 '0' 来表示而不使用 48 表示。还有就是 'a' 和 'A' 的编码也可以记一记。

    我们回到这个题目的题解,当 num[17] == 'X' 的时候,我们将 num[17] 赋值为 ('9' + 1) , '9' 的编码加一,查表发现对应的是 ':' ,但是我们这里只是判断结果 sum 是否为 10,我们可以 (':' - '0') 来表示 10 对吧,实在不理解就是(58 - 48)。同理可得到,前面那些 ( - '0' )的操作就是将ASCII码的编码减小成为对应的整数,来进行数学运算。

    其实在我们学习中,很多时候会遇到,输入的是字符型的数字,但是我们要用其进行数学运算,就像是我们想表达 (9 + 1)结果为 10 ,但是我们使用字符来表达 ('9' + '1')其计算方式就是编码相加(57 + 49)结果不言而喻了吧!此时我们做一个操作(('9' - '0') + ('1' - '0'))不就可以将字符当作整数做运算了吗。

    另外一个值得记住的点就是大小写字符之间的关系,细心的同学在看表的时候已经发现了,大小写字符在表格中的位置是一一对应的,我们将其做差和明显的发现,他们之间的差值是 32 ,基于这个特点我们常常用来做字母大小的转换。

    Information

    ID
    41
    Time
    1000ms
    Memory
    256MiB
    Difficulty
    8
    Tags
    # Submissions
    1800
    Accepted
    230
    Uploaded By