题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3398
对于这种有点巧妙的递推还是总是没有思路...
设计一个状态 f[i] 表示第 i 位置上是公牛,那么 f[i] = ∑(0<=j<i-k) f[j];
再前缀和优化一下即可。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const maxn=1e5+5,mod=5000011; int n,k,f[maxn],s[maxn]; int main() { scanf("%d%d",&n,&k); f[0]=1;s[0]=1; for(int i=1;i<=n;i++) { f[i]=(s[max(0,i-k-1)])%mod; s[i]=(s[i-1]+f[i])%mod; } printf("%d",s[n]); return 0; }
当然也可以用组合数:https://www.cnblogs.com/harden/p/6286182.html
(注意取模与 (ll) 与加括号的艺术...)
代码如下:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long ll; ll ans; int n,k,mod=5000011; int pw(int a,int b) { int ret=1; for(;b;b>>=1,a=((ll)a*a)%mod) if(b&1)ret=((ll)ret*a)%mod; return ret; } int C(int n,int m) { int a=1,b=1; for(int i=n-m+1;i<=n;i++) a=((ll)a*i)%mod; for(int i=1;i<=m;i++) b=((ll)b*i)%mod; return ((ll)a*pw(b,mod-2))%mod; } int main() { scanf("%d%d",&n,&k); for(int i=0;i<=n;i++) { int m=n-(i-1)*k; if(m<i)break; ans=((ll)ans+C(m,i))%mod; } printf("%d",ans%mod); return 0; }