zoj3725 组合数学,递推

链接: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;
}
原文地址:https://www.cnblogs.com/54zyq/p/3205135.html