牡牛和牝牛 LibreOJ - 10230

原题链接

考察:计数dp

思路:

        虽然之前接触过计数dp,但是碰到这种题第一反应除了组合数之外毫无想法,今天学计数dp才发现不止组合数这一知识点.

        有两种方法.以不同的划分状态依据.

方法一:

        定义 f[i] i头牛并排站的方案数.以最后一头牛是什么品种来划分.如果最后一头牛为A牛,则剩下的i-1头牛不需要care第i头牛方案数为f[i-1]

如果为b牛,则上头b牛之间必须隔k头a牛,方案数为f[i-k-1].

        如果i<=k+1,则f[i] = i+1.

方法一
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010,M = 5000011;
int f[N],n,k;
int main()
{
    scanf("%d%d",&n,&k);//i头牛排成一排,以最后一个为划分依据
    for(int i=1;i<=k+1;i++) f[i] = i+1;
    for(int i=k+2;i<=n;i++) f[i] = (f[i-1]+f[i-k-1])%M;
    printf("%d\n",f[n]);
    return 0;
}

方法二:

       定义f[i]为 第i头牛为b牛的方案数.这种需要用前缀和优化.

方法二
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010,M = 5000011;
int f[N],n,k,s[N];
int main()
{
    scanf("%d%d",&n,&k);//i头牛排成一排,以最后一个为划分依据
    // for(int i=1;i<=k+1;i++) f[i] = i+1;
    // for(int i=k+2;i<=n;i++) f[i] = (f[i-1]+f[i-k-1])%M;
    // printf("%d\n",f[n]);
    /*s[i]为f[1~i]的前缀和*/
    f[0] = 1,s[0] = 1;
    for(int i=1;i<=n;i++)
    {
        f[i] = s[max(i-k-1,0)];
        s[i]= (s[i-1]+f[i])%M;
    }
    printf("%d\n",s[n]);//不需要-1,存在没有a牛的情况.
    return 0;
}
posted @ 2021-06-10 15:35  acmloser  阅读(75)  评论(0编辑  收藏  举报