牡牛和牝牛 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;
}