11届广东省acm 有为杯 boring sequence

来源:互联网 发布:海鹰数据速卖通 编辑:程序博客网 时间:2024/05/16 07:32

****J题:看了大神的总结

来自http://blog.csdn.net/fanfank/article/details/8923215

http://www.cnblogs.com/IT-BOY/archive/2013/05/13/3076442.html

给定N和K,整数序列S如果同时满足下面3个条件,那么就称之为沉闷序列:

1. 数列有N个整数

2. 每个整数要么是0,要么是1

3. 同样的数字连续出现K次以上(即K+1或以上次)

例如N=3,K=2,那么111和000都是沉闷序列。计算给定N和K在范围[1,1000]下的沉闷序列数量,最终结果对1007取模。

这题计算时要转换一下思路,首先计算非沉闷序列的数量,然后再用2^n减去非沉默系列的数量即可得到答案。计算非沉闷序列时,需要使用动态规划,后来子畦跟我说这题时,我的感觉就是——丫这动态规划的转移式太秒了,我肯定想不出来,怎么办?子畦语重心长地回答:“靠经验,靠积累吧。”

我们用f[i][j][0]表示到数列的第i个位置(从0开始)连续j个都是0(从(i-j+1)~i)的情况数,f[i][j][1]则是连续j个1,状态转移方程如下:

f[i][j][0] = f[i-1][j-1][0]

f[i][j][1] = f[i-1][j-1][1]

f[i][1][0] = f[i-1][k][1],其中k从1~K

f[i][1][1] = f[i-1][k][0],其中k从1~K

/* * 定义 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串的题基本都是从最后开始递推,累加。优化方式有快速幂等。 */


原创粉丝点击