Hoodlum1980 (fafa)'s Technological Blog

Languages mainly using and digging: C / CPP, ASM, C#, Python. Other languages:Java.

博客园 首页 新随笔 联系 订阅 管理

        星期天这天一口气AC了五道题,除了1009外基本都可算是简单题。

       (1)1009 Enigma

       http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1009

       题目是讲解二战期间德国使用的密码机Enigma。明文通过按键,通过转盘(rotor)转换为密文。如下图所示为有1个转盘,一共有6个字母的情况,每击键一次,转盘转动一格。如果含有多个转盘,则以类似数字进制方式转动,即第一个盘转动一圈后,第二个盘转动一格,以此类推。题目要求解密含有三个转盘的密文,第一行输入m,表示键盘一共有m个字母('A','B','C',...,'A'+m-1),然后输入三行表示每个转盘的初始字符映射状态(例如下图中的rotor的初始状态是BADFEC)。然后输入n行密文,要求输出每个密文的明文。

     

        分析上面的图,可得转盘的输入x和输出x'之间的关系是偏移关系,即x'=x+dx;因此我们把映射关系中的偏移量dx用一个数组表示:

        int rotor[m]; 这个数组中的负数也可以通过加上m矫正为正数。

        例如上图中的映射关系为BADFEC,用偏移量数组表示为{1, -1, 1, 2, 0, 3},

        当rotor转动一格时,相当于该数组循环向右移动一格,变为{3, 1, -1, 1, 2, 0};

        因此我们完全物理模拟rotor的转动过程,给出第一个版本的AC的代码如下:

1009_Version_01

       上面的代码用时190ms,而该题的解排行榜的用时为20ms,30ms,40ms。可见运行时间还可以改进,我想运行时间的改进可能是主要针对常数因子的改进。因此我们考虑上面的代码中的导致效率低下的地点所在。大致可以确定是每敲打一次按键,对rotor转动时需要对数组进行如下操作:字符串->偏移值数组->数组元素转动->字符串,虽然字符串长度不大,但它的耗时属于O(n),因此我们可以把这个过程改为O(1)。即我们不实际转动数组元素,而是利用一个标记当前的totor位置的“指针”,这样rotor转动时,我们仅仅改变“指针”的值,而不需要移动数组。

         为了快速求取输入,我们把上面的数组可以认为是函数f(x),我们现在把该数组改为f的反函数即f'(x)。即:

         f(x):  {1, -1,  1,  2,  0,  3};      (明文)abcdef    ->   BADFEC (密文)

         f'(x): {1, -1,  3, -1,  0, 4};       (密文)ABCDEF  ->   bafced   (明文)

        这样,我们就能根据密文,直接得到明文。因此我们得到第二个版本的代码如下:

1119_Version_02

      版本2的运行时间为50ms,(两个版本的内存占用都是100多K,属于小空间),因此这个解无法上榜。暂时没有想到进一步提高速度的方法,因此这道题暂且就到这里了。

         ---------------------------------------------------------------------------------------------

        (2)1115题:Digital Roots

         http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1115

         题目要求计算一个正整数的digital root,也就是计算一个10进制正整数n的所有位的和,如果结果不是一位数,继续计算,直到得到一位数为止,称为n的digital root。例如当n=39,则求取过程如下:3+9=12, 1+2=3;即digital root (39) = 3;

         可见此题相当简单,但是这个题有一个小小的“注意事项”,就是输入的n可能很大,因此在读取输入时,我们不能当作一个普通数据类型读入,而是用一个字符串整体读入,求出第一次的数位和以后即可用常规数据类型计算。代码如下:

1115_digital_root

          ---------------------------------------------------------------------------------------------

          (3)1476 Weird Clock(怪异钟)

          http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1476

          题目很简单,一个钟只有分针(仅能表示0~59分),它自己不会走,只有投入一种硬币,它才会走。硬币上标有一个数字d,则该钟向前走当前时间s(分钟)的d倍,例如当时钟分针为45分钟时(s=45),投入d=2的硬币,该钟将向前走45*2=90分钟,指向15分。现在输入时钟的当前分钟,和硬币上的数字d,问最少投入多少个这样的硬币后指针指向0点,如果永远不可能指向0点,则输出impossible。

         这个问题实际上很简单,但是我们需要谨慎考虑impossible的情况,否则我们的代码可能会陷入死循环!考虑impossible的情况,必然是在旋转落点上进入了重复,即在投入一些硬币后,分针重新指向此前已经达到过的分钟数,这时即永远无法指向0点。因此我们用一个flag数组标记分针已经到达过的位置,只要分针到达的位置重复,就说明是impossible的情况,例如分钟为10,d=2时,分钟的轨迹为:10->30->30->30->...。代码如下:

1476_weird_clock

         ----------------------------------------------------------------------------------------------

         (4)1733:Common Subsequence (最长公共子序列问题)

          http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1733

          该题属于动态规划经典命题之一,算法书都会讲到,因此我原样引用了《软件设计师教程》书中的代码。需要注意的是,这个代码比较原始,空间效率不高,可以进一步改进。代码原理就不解释了。

1733_common_subsequence

           --------------------------------------------------------------------------------------------

         (5)2405 Specialized Four-Digit Numbers

           http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2405

           题目描述也很简单,求出所有满足下列条件的4位数(10进制),该数字用10进制,12进制,16进制表示时,数位和相等。例如2992是第一个满足条件的数字,12进制为1894,16进制为BB0, 2+9+9+2 = 1+8+9+4 = B+B+0 =22;该题属于典型简单题,穷举即可,无须解释,代码如下:

2405_specialized_four_digit_numbers
posted on 2008-10-20 21:51  hoodlum1980  阅读(1945)  评论(0编辑  收藏  举报