bzoj 3398 [Usaco2009 Feb]Bullcow 牡牛和牝牛——前缀和优化dp / 排列组合
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3398
好简单呀。而且是自己想出来的。
dp[ i ]表示最后一个牡牛在 i 的方案数。
当前位置放牝牛,之前的dp[ k ]不变;当前位置放牡牛,出现了dp[ i ],值是距离大于k的dp[ j ]的和,所以可以前缀和优化。
当然有dp[0]啦。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1e5+5,mod=5000011; int dp[N],c[N],n,k; int main() { scanf("%d%d",&n,&k); dp[0]=1;c[0]=1; for(int i=1;i<=n;i++)dp[i]=c[max(0,i-k-1)],c[i]=(c[i-1]+dp[i])%mod; printf("%d\n",c[n]); return 0; }
但是这其实是排列组合的题目。https://www.cnblogs.com/harden/p/6286182.html
逆元不预处理而是现弄其实也挺方便的。“古代猪文”那道题预处理阶乘逆元似乎爆了什么。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=1e5+5,mod=5000011; int n,k,jc[N],ans; void init() { jc[0]=1; for(int i=1;i<=n;i++)jc[i]=(long long)jc[i-1]*i%mod; } int pw(int x,int k) { int ret=1;while(k){if(k&1)ret=(long long)ret*x%mod;x=(long long)x*x%mod;k>>=1;}return ret; } int C(int i,int j) { return (long long)jc[i]*pw(jc[j],mod-2)%mod*pw(jc[i-j],mod-2)%mod; } int main() { scanf("%d%d",&n,&k); init(); int lm=n/(k+1)+1-(n%(k+1)==0); for(int i=1;i<=lm;i++)(ans+=C(n-k*(i-1),i))%=mod;// no i=0 printf("%d",(ans+1)%mod); return 0; }