九度1084解题报告

来源:互联网 发布:网络编程能自学么 编辑:程序博客网 时间:2024/05/21 22:24

http://ac.jobdu.com/problem.php?pid=1084 整数拆分的题。

根据这几天的做清华真题的情况,可以看出,清华超爱出数学类的题目,考察学生的数学基础和找规律的能力。这道题,乍一看是要找个什么公式或者规律来解决,其实仅仅用dp就可以解决,也就是说,要找出拆分种类的递推规律。本题主要有两条规律,即要分奇偶讨论。

当要拆分的数为奇数时,其拆分种类与上一个偶数相同,其实就是在上一个数的各拆分上+1,我一开始怀疑,如果原拆分中也含1,将两个1换成一个2,会不会又是一种新的拆分,事实上不会,因为偶数的拆分中1一定是成对出现的,如果新加的1与原来的一个1凑成一对,那么把多出来的一个单1去掉,一定是上一个偶数的一个拆分。因此,一个奇数的拆分与它上一个偶数的拆分一定一样多。这个规律比较明显。

而当要拆分的数为偶数时,规律就比较难找了。上一个奇数的各拆分加1肯定构成新的拆分,而上一个奇数的带不成对1 的拆分,与新加的1凑成一对,也构成新的拆分,进而不断向上凑,很难得出有多少拆分。于是,我们考虑另一种分类方法:将拆分分为带1的拆分和不带1的拆分。不带1的拆分,最小数为2,故整个拆分可以被2整除,因此数n不带1的拆分数应该和n/2的所有拆分相等。而带1的拆分,其实和上一个奇数相同,因为带1的拆分至少有两个1,去掉一个1后,即n-1的拆分。

找到了规律,用dp就很方便了,代码如下:

#include <stdio.h>#define MAX 1000002#define MOD 1000000000long long dp[MAX];int main(){dp[0]=dp[1]=1;for (int i=1;i<=500000;++i){dp[2*i]=(dp[2*i-1]+dp[i])%MOD;dp[2*i+1]=dp[2*i]%MOD;}int n;while (scanf("%d",&n)!=EOF){printf("%lld\n", dp[n]);}return 0;}


0 0
原创粉丝点击