今年是我第一次参加省级的比赛,发来的通知上说是ACM ICPC江苏省区比赛,但是去了那边变成了大学生程序设计大赛,去掉一个I的差别可很大。不过虽然不是International,不过难度也不少。今天就先分析其中一道题目:
题目是英文的,这里我就把翻译好的给大家,翻译不好还请见谅
给出一个正整数n(1<=n<=2001)。在n的左边可以放置另外一个数m,这样就组成一个新数mn,其中m必须小于等于n的一半。如果还有一个整数k<=m/2,那么还可以继续组成一个新数kmn....
比如有一个数12,你就可以在这个数左边放1~6,组成112,212.....612,接下来212又可以继续分成1212。
在举一个例子n=8
第一轮产生:18,28,38,48
第二轮18:不能产生新数
第三轮28:128
第四轮38:138
第五轮48:148,248
第六轮128、138、148:不能产生新数
第七轮248:1248
第八轮1248:不能产生新数
Input:
输入一个数n
Output:
一共产生了多少数
Input:
8
Output:
10
这道题目这一看之下有点像一个多叉树,第一次我想了一下,发现可以用递归做。因为我们可以看到当n=8时有4个新数,n=4时有2个新数,n=2时有一个新数,n=1时没有新数。代码如下:
递归的潜在效率损失的确很大,测100前还没有什么性能差别,但是测到400,500的时候和动态规划的性能差别已经很大了(这个是事后的测试了)。当时比赛提交以后被判为“超时”,这个结果已经是我料到的。当时浙江师范和复旦大学的队伍给了我很大的压力。好不容易清醒下来,重新看了下题目。想到一道北大上做过的题目“Function Run Fun”,这道题目一开始也是用递归做,结果超时,最后是用动态规划做出来的。
仔细研究题目时候,发现
当n=0时有0个新数,
当n=1时1个新数,
当n=2时2个新数,
当n=3时2个新数,
当n=4时4个新数,
当n=5时4个新数,
当n=6时6个新数
当n=7时6个新数,
当n=8时10个新数。
打表之后发现
n8=n1+n2+n3+n4+1=1+2+2+4+1=10
n7=n1+n2+n3+1=1+2+2+1=6
....
n4=n1+n2+1=1+2+1=4
得到这个结论之后就能打表做了,开辟一个2002大小的double数组,初始化好之后直接访问就可以了。代码如下
利用打表的方法是空间换速度,直接寻址的速度还是非常可观的,最后这道题终于AC了。