【BZOJ】【3398】【USACO 2009 Feb】Bullcow 牡牛和牝牛
组合计数/乘法逆元
排列组合求总方案数
这个可以用一个一维的动态规划解决:
f[i][0]表示第i头牛是牝牛的方案数
f[i][1]表示第i头牛是牡牛的方案数
则转移为:f[i][0]=f[i-1][0]+f[i-1][1];
f[i][1]=f[i-K-1][0]+f[i-K-1][1];
常数优化:将取模运算改为if判断语句……可从20ms降为16ms
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************************** 2 Problem: 3398 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:16 ms 7 Memory:1588 kb 8 ****************************************************************/ 9 10 //BZOJ 3398 11 #include<cstdio> 12 #define F(i,j,n) for(int i=j;i<=n;++i) 13 int getint(){ 14 int v=0,sign=1; char ch=getchar(); 15 while(ch<'0'||ch>'9') {if (ch=='-') sign=-1; ch=getchar();} 16 while(ch>='0'&&ch<='9') {v=v*10+ch-'0'; ch=getchar();} 17 return v*=sign; 18 } 19 const int N=100086,P=5000011; 20 int f[N][2],n,K; 21 int main(){ 22 n=getint(); K=getint(); 23 f[1][0]=f[1][1]=1; 24 F(i,2,n){ 25 if(i-K-1>0) f[i][1]=f[i-K-1][0]+f[i-K-1][1]; 26 else f[i][1]=1; 27 f[i][0]=f[i-1][0]+f[i-1][1]; 28 if(f[i][0]>=P) f[i][0]-=P; 29 if(f[i][1]>=P) f[i][1]-=P; 30 } 31 printf("%d\n",(f[n][0]+f[n][1])%P); 32 return 0; 33 }
2015年2月6日 15:38:06
UPD: 本题也可用排列组合的方式计算
枚举牝牛的数量a,那么一定至少有(a-1)*k头牡牛,那么除掉这(a-1)*k头牡牛,还剩下b=n-(a-1)*k-a头牡牛。
这a头牝牛和b头牡牛是随便排的……也就是求一个多重全排列 即 (a+b)! / a!*b!
这里的除法需用逆元来算
逆元的计算方法是:已知a、p,求x满足 a*x≡1 (mod p) 那么根据费马小定理(或欧拉定理)可知x= pow(a,p-2)
ps:由于我的方法是O(n)预处理出来所有的阶乘,所以时间复杂度上甚至不如上面那种DP的方法……求大神指导本题0msAC的正确姿势TAT
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /************************************************************** 2 Problem: 3398 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:24 ms 7 Memory:2052 kb 8 ****************************************************************/ 9 10 //BZOJ 3398 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<iostream> 15 #include<algorithm> 16 #define rep(i,n) for(int i=0;i<n;++i) 17 #define F(i,j,n) for(int i=j;i<=n;++i) 18 #define D(i,j,n) for(int i=j;i>=n;--i) 19 using namespace std; 20 int getint(){ 21 int v=0,sign=1; char ch=getchar(); 22 while(!isdigit(ch)) {if(ch=='-') sign=-1; ch=getchar();} 23 while(isdigit(ch)) {v=v*10+ch-'0'; ch=getchar();} 24 return v*sign; 25 } 26 /*******************template********************/ 27 typedef long long LL; 28 const int P=5000011; 29 LL pow(LL a,LL b,LL P){ 30 LL r=1,base=a%P; 31 while(b){ 32 if (b&1) r=r*base%P; 33 base=base*base%P; 34 b>>=1; 35 } 36 return r; 37 } 38 LL p[100086]; 39 int main(){ 40 LL n=getint(),k=getint(); 41 p[0]=p[1]=1; 42 F(i,2,n) p[i]=p[i-1]*i%P; 43 LL ans=1+n;// 当a=0 ans=1,a=1,ans=n 44 F(i,2,n){ 45 LL a=i,b=n-(i-1)*k-i; 46 if (b<0) break; 47 ans=(ans+p[a+b]*( pow(p[a]*p[b]%P,P-2,P) )%P)%P; 48 } 49 printf("%lld\n",ans); 50 return 0; 51 }