1
理解这个程序就是从输出的地方入手即可。这个程序输出的条件是hit==2&&(hit1+1==hit2),而hit表示满足i%r[j]!=0的条件的次数,hit==2表示这个条件只能被满足两次,也就是说对于一个i,在rg数组的30个数中,这个i能被其它28个数整除,而不能被其中两个数整除。而hit1表示第一个不能整除i的数的下标,hit2表示第二个不能整除i的下标,这两个下标被要求相差只有1。
所以,程序所要寻找的是这样的数:这个数i不能被2-31这30个数中的两个相邻的数整除,但能被其它 28个数整除。
这里我们需要找到这两个相邻的数。设这两个数分别为A,A+1,如果i不能被A整除,那么,i必然不能被A的倍数整除。所以A必然大于15(因为给定的数的范围是2-31),即i必然能够被2-15之间的数整除,而18=2*9,20=4*5,22=2*11,。。。30=2*15。因为i必然能够被2-15之间的数整除,所以i,必然能够被18,20,。。。30这些数整除。那么最后只剩下16和17。所以,所求的i肯定不能被16和17整除,同时能够被其他28个数整除。那么i就是其它28个数的最小公倍数的整数倍。
2.
我们先把2到31中的素数都列出来(17除外):{2,3,5,7,11,13,19,23,29,31}。而2到31中(16,17除外)的数都是由这些素数作为因子组合相乘得到的,其中,要得到8,至少要3个2,要得到27至少要3个3,要得到25,至少要2个5,其余的素因子都只需一个就够了。
因此,这个最小的数就是 2^3, 3^3, 5^2, 7, 11, 13, 19, 23, 29, 31的乘积,答案为:2123581660200。
3. 要估算时间,我们先确定一个原子操作(或者说原子过程更合适),这里我们取内层for循环里的整个if语句块,该段程序主要包括一个取模操作和一个判断,如果进入if语句的话,还包括1次加法操作,1~2次判断和一次赋值操作。
我们知道加法、判断等操作基本都在几个时钟周期内就可以完成,而除法操作却需要数十个时钟周期,而取模操作也是通过除法操作得到的(还记得汇编语言里,执行除法操作之后,一个寄存器里存结果,另一个寄存器里存余数),另外,对64位整数的除法明显要慢于32位整数,综合这些因素,我们可以假设该原子操作需要100个时钟周期。因此2GHz的CPU在1秒内能跑2*10^9 / 100 = 2*10^7 即2000万次原子操作,做过ACM的同学就会有一个直观概念,这和我们通常做时限为1S的题时估算的计算次数差不多。
接下来估算原子操作执行的次数:外层循环跑了2123581660200次,内层循环取决于 i 的情况,当i为奇数的时候,内层最多跑5次即可结束,因为2,4,6都不能整除奇数;当i为偶数的时候,情况要复杂一些,但是也可以一个一个的详细分析。这里我们粗略估计,就算内层循环平均可以跑10次,外层循环少跑一些,去掉零头,总的原子操作执行了2*10^13次。
所以需要 2*10^13 / (2*10^7) = 10^6秒约为277个小时。