http://202.197.224.59/OnlineJudge2/index.php/Problem/read/id/1233
题意:
n个影币,问有多少种情况至少连续m个正面朝上。
思路:
注意这道题是至少,而不是恰好,理解样例的时候刚开始在这个位置就出现了问题。
dp[i][0]表示满足条件的情况数量
dp[i][1]表示不满足条件的情况数量
注意在推到的时候有一个状态是i-1-m,这个状态是前i-1不满足情况且前i-1-m也不满足情况状态,这时连续的位置就是算上新更新的这个位置之后,也就是说它之前恰好有连续m-1个正面朝上,(第i-m个是反面朝上)注意情况不要重叠就ok了!算上新位置正好满足!
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int N=1e6+10;
const LL MOD=1e9+7;
LL dp[N][2];
LL a[N];
int main()
{
int t,i,j,n,m;
a[0] = 1;
for(i = 1; i<N; i++)
a[i] = ((LL)2*a[i-1])%MOD;//n个硬币一共有n^2个状态
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
dp[m][0] = 1;//初始值,只有m个硬币呢么必须全部面朝上,只有1种
dp[m][1] = (a[m]-dp[m][0]+MOD)%MOD;//总方案数减去面朝上的方案数为不可行的
for(i = 0; i<m; i++)//不足m个,则为全状态
dp[i][1] = a[i];
for(i = m+1; i<=n; i++)
{
/* i个满足的状况首先从i-1个枚举来,i-1的状态满足的话,那么再加一个硬币可正可反,所以dp[i-1][0]*2 然后还要加上dp[i-1-m][1],这是对于连续m个面朝上看做一个整体,然后包括剩下不可行的方案数 */
dp[i][0] = ((dp[i-1][0]*2+MOD)+dp[i-1-m][1])%MOD;
dp[i][1] = (a[i]-dp[i][0]+MOD)%MOD;
}
printf("%I64d\n",dp[n][0]);
}
return 0;
}