Code Jam 2010:http://code.google.com/codejam
Snapper Chain
其实这是一道英语阅读理解题,真的。只要读懂了就能轻松的做出来。
Snapper是一种带电子开关的插线板(我的理解)。它的一边是插头另一边是插孔。电子开关有两种状态:开和关,只有当插头通电是开关才能切换状态,且插头断电后开关状态保持不变。现在有N个snapper连接成一条链,链的一段连接在电源上,另端连接一个台灯。所有snapper的初始状态都是关。每次操作会触发所有snapper的开关,问这样执行K次操作后,台灯是不是亮的。
OK,我们可以用0和1来表示snapper的两种状态。这样就可以将snapper chain表示成为一个N bits的数,如下:
台灯-00000000-电源
每次操作时,第 i 位snapper的状态只有满足 右边是电源或者右边全是1 才会变化。
这样就可以列出一个操作次数和snapper的对应表:
K Snappers
1 00000001
2 00000010
3 00000011
4 00000100
这样,规律就一目了然了。所以只有当K的最低N位全是1,台灯才会亮。
读懂了题目就只需要一行代码就能够算出来了。
Fair Warning
这是这一轮里最困难的一道题了。
给定N个正整数t1,t2...tn, 求一个y的最小值,使得所有 ti + y 都有一个共同的最大公因数T,且T的值最大。
设有两个正整数a,b 且 a > b 。 a + y 和 b + y的最大公因数是T。则可以表示为
a + y = pT
b + y = qT
p,q为整数且 p > q
所以 (a + y) - (b + y) = (p-q)T = a - b ,换而言之呢,a-b 和 a + y 和 b+y 的最大公因数都是T。
a + y的值虽然不知道, 但是 a-b 却是已知的。
将给出的N个数字两两相减, 所有的差的最大公因数就是T。而知道T以后呢,y就可以很轻松的算出了。
具体的代码如下(由google给出,比我的算法简单很多):
说句题外话,google果然还是偏向pythoner的,这道题要处理1050的数字,这对python来说无所谓,但是对于其他的语言就需要专门的大数库了。
Theme Park
这道题目的large input拥有所有题目里的最低正确率40%,算法的时间复杂度不好就肯定在8分钟内计算完。
游乐场的过山车的容量是K,每天运行R次,有N组人排队,每组的人数是gn ,组不能拆分,当过山车容不下下一组的时候就开始运行。坐完的人会按照开始的顺序重新排到队尾(真是好顾客)。每人每次1欧元,问一天能收入多少钱?
很简单的题目对吧,
这的算法的复杂度是O(NR), 解决small input肯定没问题,但是large input里:
1 ≤ R ≤ 108
1 ≤ N ≤ 1000
在规定的时间里决定算不完(你要是有一台深蓝那样的电脑请当我没说)。
观察算法可以发现每次从位置i开始进人,一定会到位置j结束。我们可以把这个提前算出了,新算法如下:
这样算法的复杂度变成了O(N),在large input的时候比上一个算法提高了1000倍。但是这个还不够好。
事实上我用的就是这个算法,在最后30内才算完(幸好超频了CPU)。
通过分析题目, 可以发现在R > N的时候存在必定存在一个循环,即从一个位置i开始,经过x轮后,又从i开始。
这样R次循环就可以分成3部分:
1 经过m轮后,到达位置i
2 经过x轮,有回到i, 循环n次
3 不够一个循环的p轮
m和p的值都很小,很容易求得1和3阶段的收入 u,w
2阶段的收入就是 n * v 其中v是每个循环的总收入
具体代码如下:
总结:
Code jam 的small input和large input, 分别考察的是算法的正确性和算法的效率。一般而言会有多种方法解出small input, 但是对于large input,高效的算法一般都能够在很短的时间内完成。而没有优化的算法基本都会超时。所有,确保算法正确性的同时必须考虑算法的效率。