链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3725
题意:有n个格子,只能涂红、蓝两种颜色。要求至少有m个连续的格子涂上红色,求有多少种方法。
思路:一开始是直接算,结果T了,不得不转变思想。要求至少m个格子连续的话,可以枚举连续m个格子的首位置。假如第i个格子开始往后的m个格子都是红色的,则后面的(n-(i+m)+1)个格子随意涂,有2^(n-(i+m)+1)种。此时第i-1个格子必然要为蓝色。且要求在前面的1到i-2个格子中不能有连续m个红格子。计前面i-2个格子有b[i]种放法。当i<m时,肯定不会出现连续m个红格子,所以随意放,b[i]= 2^i种放法。当i>=m时,b[i]=b[i-1]+b[i-2]+...+b[i-m],b[i+1]=2*b[i]=b[i-m],所以得到递推式b[i]=2*b[i-1]-b[i-m-1].当i-m-1<0时,b[i-m-1]=1.最后的话就用b[i-2]*a[n-m+1-i]求和就可以了。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int maxn=100000+5; const int mod=1000000007; LL a[maxn],b[maxn]; int main() { int n,m; LL ans; a[0]=1; for(int i=1; i<maxn; i++) a[i]=(a[i-1]*2)%mod; while(~scanf("%d%d",&n,&m)) { ans=0; b[0]=1; for(int i=1; i<m; i++) b[i]=a[i]; for(int i=m; i<=n; i++) { LL c; if(i-m-1>=0) c=b[i-m-1]; else c=1; b[i]=((2*b[i-1]-c)%mod+mod)%mod; } for(int i=1; i<=n-m+1; i++) { LL c; if(i==1) c=1; else c=b[i-2]; ans=(ans+(c*a[n-m+1-i])%mod)%mod; } printf("%lld ",ans); } return 0; }