网教16. 电话号码问题

<pre name="code" class="cpp">

 商业单位需要容易记忆的电话号码,有一些方法可以让电话号码变得更容易记忆。譬如,可以把电话号码写成单词或短语,如 MON-GLOP 可以代表滑铁卢大学的电话。有时仅仅是把号码的一部分写成单词,如打 310-GINO 便可向 GINO 比萨饼店定购比萨。另一种让电话号码容易记忆的方法是将数字用一种容易记的方式组合起来,譬如 3-10-10-10 也可以代表 GINO 比萨饼店。 
  

电话号码的标准形式是七位十进制数字,在它的第三位和第四位之间用连字符连接(例如:666-1200)。电话的键盘提供了字符与数字之间的映射关系,如下所示:

2A、B和C 
3D、E和F 
4G、H和I 
5J、K和L 
6M、N和O 
7P、R和S 
8T、U和V 
9W、X和Y 

Q 和 Z 没有映射到键盘,而连字符不需要被拨打并且可以根据需要添加和删除。MON-GLOP 的标准形式是 666-4567,310-GINO 的标准形式是310-4466,3-10-10-10的标准形式也是 310-1010。

如果两个电话号码有相同的标准形式,那么这两个电话号码是相同的。

你所在的公司正在编辑一本当地商业单位的电话簿,作为质量控制流程的一部分,你需要确认在该电话簿中有没有错误的电话号码,以及有没有两个(或两个以上的)商业单位使用相同的电话号码。由于当地只使用了 3 和 6 两个区段,因此电话号码的第一个数字应当永远是 3 或者 6,如果出现了其它数字,就表示这个电话号码错了。此外,如果电话号码中出现了 Q 和 Z,也说明这个电话错了。

输入

一次输入为一个样例。每个号码一行,每行的字符不会超过 20 个。每次输入的数据可能会非常大,譬如超过 1,000,000 个电话号码。

你可以假设输入中可能会出现重复的电话号码不超过 1,500 个,每个号码重复的次数不超过 1000 次。

输出

输出包括两个部分,第一个部分是错误的电话号码,对于这些号码应当按照输入的顺序以原始的形式输出。在输出错误电话号码前输出“Error:”,随后输出这些号码,如果没有错误的电话号码,则输出“Not found.”。

第二部分是重复的电话号码,对每一个在电话簿中以任何形式出现一次以上的电话号码,生成一行输出。这一行应以标准形式给出电话号码,其后跟随一个空格,空格后跟随电话号码在电话簿中出现的次数。所有重复的电话号码输出行应以号码的升序排列(小号码在前)。在输出重复电话号码前输出“Duplication”,随后按照上述格式输出号码,如果在输入中没有重复的电话号码,则输出:“Not found.”。

注意

你所编写的程序以后可能会在一种特殊的嵌入式设备上运行,为了降低成本,这种设备使用的 CPU 不是很快、可用的 RAM 为 288K(跟 GBA 一样)且它没有磁盘设备因此不能使用文件作为数据的临时存储。

提示

请参考《编程珠玑》第一部分,若程序不能在规定的内存中运行,则不得分。

  测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 4873279↵
  2. ITS-EASY↵
  3. 666-4567↵
  4. 3-10-10-10↵
  5. 666-GLOP↵
  6. MON-GLOP↵
  7. 367-11-11↵
  8. 310-GINO↵
  9. F101010↵
  10. 666-1200↵
  11. -4-8-7-3-2-7-9↵
  12. 487-3279↵
以文本方式显示
  1. Error:↵
  2. 4873279↵
  3. ITS-EASY↵
  4. -4-8-7-3-2-7-9↵
  5. 487-3279↵
  6. Duplication:↵
  7. 310-1010 2↵
  8. 666-4567 3↵
1秒 512KB 0
测试用例 2 以文本方式显示
  1. 3456789↵
以文本方式显示
  1. Error:↵
  2. Not found.↵
  3. Duplication:↵
  4. Not found.↵
1秒 512KB 0
题解:
炒鸡坑的一道题。
一开始没读懂题目,然后就一直RE。。我还傻乎乎地改大数组,还是RE,心里还各种懵逼。。就这样re了30发,度过了6个小时。。后来看了暾神推荐给我的博客才明白,这个题是会有1e6条电话,但是可能出现两次及以上的只有1500个,所以只用存这1500个就够了。然而如何判断它是否重复了呢?以前那样每个数都存肯定是不行了,会爆内存,所以只能换个方法。13级大神邵凯阳的博客里写了个方法:
用一个unsigned char型的数组或是unsigned int型的数组来存储,如果用char来存储,先将电话号码判断之后转化为一个百万大小的数字,然后由于首位不是3就是6,所以取后面的6位进行存储即可。假设这个数是i,那么就可以用c[i/8]=c[i/8]|1<<i%8来进行标记,可以通过判断c[i/8]&1<<i%8是否大于0来判断这个电话是否存在。
c数组开125000(防止爆内存),储存6开头的,还有一个b储存3开头的。一开始初始化的时候让c数组是0,所以在第一次访问的时候 c[i/8]&1<<(i%8)肯定是0.如果它是0,就要标记一下让程序知道它已经被访问过了,这时就 c[i/8]=c[i/8]|1<<(i%8)。由于开的是125000=1e6/8,所以t=i/8,t有可能会是8个数(8*t+0/1/2/3/4/5/6/7),然后再用i%8来标记,因为k=i%8,那么i=8*t+k。让1向左移k个单位,那么之后c[i/8]=1<<(i%8)。下次再走到这个i的时候,c[i/8]=1<<(i%8),和1<<(i%8)再进行&运算的时候值就是1<<(i%8)了。用这个来记录是否是第一次访问这个数,感觉很厉害。
附一个位图法算法:
位图法 http://www.jb51.net/article/54949.htm
还有一件事,谁能还我的50小时的罚时 难过 微笑笑着活下去
AC代码:
#include<stdio.h>   
#include<string.h>   
#include<stdlib.h>   
#include<math.h>   
#define maxe 35000   
struct node  
{  
    int a[2];  
};  
int comp(const void *a, const void *b)  
{  
    return(((struct node *)a)->a[0] - ((struct node *)b)->a[0]);  
  
}  
int main()  
{  
    struct node tele[1505];  
    char tmp[25];  
    unsigned char b[250005] = { 0 }, c[250005] = { 0 };//b储存3开头,c储存6开头   
    int i = 0;  
    int flag1 = 0, flag2 = 0, flag3 = 0;  
    int j, num, t, tt, x, y, len;  
    int n;  
    printf("Error:\n");  
    while (gets(tmp) != NULL)  
    {  
        j = 0;  
        flag3 = 0;  
        while (tmp[j] == '-')  
            j++;  
        if (tmp[j] != '3'&&tmp[j] != 'D'&&tmp[j] != 'E'&&tmp[j] != 'F')  
        if (tmp[j] != '6'&&tmp[j] != 'M'&&tmp[j] != 'N'&&tmp[j] != 'O')  
        {  
            printf("%s\n", tmp);  
            flag1 = 1;  
            continue;  
        }  
  
        len = strlen(tmp);  
        for (tt = 0; tt < len; tt++)  
        if (tmp[tt] == 'Q' || tmp[tt] == 'Z')  
        {  
            printf("%s\n", tmp);  
            flag3 = 1;  
            flag1 = 1;  
            break;  
        }  
        if (flag3)  
            continue;  
  
        for (tt = 0; tt < len; tt++)  
        if (tmp[tt] == 'A' || tmp[tt] == 'B' || tmp[tt] == 'C')  
            tmp[tt] = '2';  
        else if (tmp[tt] == 'D' || tmp[tt] == 'E' || tmp[tt] == 'F')  
            tmp[tt] = '3';  
        else if (tmp[tt] == 'G' || tmp[tt] == 'H' || tmp[tt] == 'I')  
            tmp[tt] = '4';  
        else if (tmp[tt] == 'J' || tmp[tt] == 'K' || tmp[tt] == 'L')  
            tmp[tt] = '5';  
        else if (tmp[tt] == 'M' || tmp[tt] == 'N' || tmp[tt] == 'O')  
            tmp[tt] = '6';  
        else if (tmp[tt] == 'P' || tmp[tt] == 'R' || tmp[tt] == 'S')  
            tmp[tt] = '7';  
        else if (tmp[tt] == 'T' || tmp[tt] == 'U' || tmp[tt] == 'V')  
            tmp[tt] = '8';  
        else if (tmp[tt] == 'W' || tmp[tt] == 'X' || tmp[tt] == 'Y')  
            tmp[tt] = '9';  
  
        tt = 0;  
        x = 0;  
        y = 0;  
        for (t = 0; t < len; t++)  
        if (tmp[t] != '-')  
        {  
            tt++;  
            if (tt < 4)  
                x += (tmp[t] - '0')*pow(10.0, 3 - tt);  
            else  
                y += (tmp[t] - '0')*pow(10.0, 7 - tt);  
        }  
        int sum = 10000 * x + y;  
  
  
        if (sum<4000000 && sum>2999999)  
        {  
            t = sum % 3000000;  
            if ((b[t/4]&1<<(t%4))!=0)  
            {  
                flag3 = 0;  
                for (j = 0; j < i; j++)  
                if (tele[j].a[0] == sum)  
                {  
                    tele[j].a[1]++;  
                    flag3 = 1;  
                    break;  
                }  
                if (!flag3)  
                {  
                    tele[i].a[0] = sum;  
                    tele[i].a[1] = 1;  
                    i++;  
                }  
            }  
            else  
            {  
                b[t/4] = b[t/4]|1<<t%4;  
            }  
  
        }  
        else if (sum>5999999 && sum<7000000)  
        {  
            t = sum % 6000000;  
            if ((c[t / 4] & 1 << (t % 4)) > 0)  
            {  
                flag3 = 0;  
                for (j = 0; j < i; j++)  
                if (tele[j].a[0] == sum)  
                {  
                    tele[j].a[1]++;  
                    flag3 = 1;  
                    break;  
                }  
                if (!flag3)  
                {  
                    tele[i].a[0] = sum;  
                    tele[i].a[1] = 1;  
                    i++;  
                }  
            }  
            else  
            {  
                c[t / 4] = c[t / 4] | 1 << t % 4;  
            }  
        }  
    }  
  
    if (!flag1)  
        printf("Not found.\n");  
  
    printf("\nDuplication:\n");  
    qsort(tele, i, sizeof(struct node), comp);  
    for (n = 0; n < i; n++)  
    if (tele[n].a[1] > 0)  
    {  
        flag2 = 1;  
        tele[n].a[1]++;  
        printf("%03d-%04d %d\n", tele[n].a[0] / 10000, tele[n].a[0] % 10000, tele[n].a[1]);  
    }  
    if (!flag2)  
        printf("Not found.\n");  
    return 0;  
}  


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值