电话号码问题

来源:互联网 发布:淘宝申请延长收货时间 编辑:程序博客网 时间:2024/05/16 15:21
商业单位需要容易记忆的电话号码,有一些方法可以让电话号码变得更容易记忆。譬如,可以把电话号码写成单词或短语,如 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秒512KB0测试用例 2以文本方式显示
  1. 3456789↵
以文本方式显示
  1. Error:↵
  2. Not found.↵
  3. Duplication:↵
  4. Not found.↵
1秒512KB0
题解:
一这个题是会有1e6条电话,但是可能出现两次及以上的只有1500个,所以只用存这1500个就够了。然而如何判断它是否重复了呢?以前那样每个数都存肯定是不行了,会爆内存,所以只能换个方法。1
用一个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)了。用这个来记录是否是第一次访问这个数,感觉很厉害。



原创粉丝点击