题目不说了,大牛眼中的水题,我等水货想都想不到。。。
直接贴代码,优化的面目全非。。。
后来没有其他测试,只测试了题目中的几个样例以及1000 999之类的,不能保证代码完全正确,欢迎排错
/* * 定义 dp[i][j][0]为长度为i以j个0结尾的串的数量 * 推出公式 * dp[i][1][0]=sum(dp[i][k][1])(1<=k&&k<=K) * 优化过程为dp[i][j]=dp[i-1][j-1],即直接加一个与串末相同字符即可 * 计算2的阶乘和计算和时,使用模运算 * 因为dp[i][j][0]==dp[i][j][1],只有dp[i][1]有用 * 继续优化空间 * 发现最终的ans和dp[n+1]是一样的求法,故终极优化 */ #include <iostream> using namespace std; const int MOD=1007; const int maxn=1002; int dp[maxn]={2,2}; int b[maxn]={0,1}; int main() { // freopen("in.txt","r",stdin); for(int i=2;i<maxn;i++) b[i]=(b[i-1]*2) % MOD; int n,K; while(~scanf("%d%d",&n,&K)) { n++; for(int i=2;i<=n;i++) { dp[i]=0; for(int k=1;k<=i-1&&k<=K;k++) dp[i]=(dp[i]+dp[i-k])%MOD; } printf("%d\n",(b[n]-dp[n]+MOD)%MOD); } }
由优化的代码产生的具象的想法:定义d[i]为连续相同字符长度不超过K的01字符串的个数,则d[i]可分为:
d[i-1]:最后字符若为0,则添加1个1,反之为1,添加1个0。
d[i-2]:最后字符若为0,则添加2个1,反之为1,添加2个0。
...
d[i-k]:最后字符若为0,则添加k个1,反之为1,添加k个0。
即 d[i] = sum(d[j])( max(1, i-k) <= j <= i-1)
01串的题基本都是从最后开始递推,累加。优化方式有快速幂等。
看了一下和以前做的杭电2604挺像,之前写的解题报告:http://www.cnblogs.com/IT-BOY/archive/2013/02/03/2890841.html