2015湘潭邀请赛 A.Coins

时间:2022-07-06 18:50:29

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;
}