牡牛和牝牛(信息学奥赛一本通 1652)
【题目描述】
原题来自:USACO 2009 Feb. Silver
牡 mǔ,畜父也。牝 pìn,畜母也。 ——《说文解字》
约翰要带 N 只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛。牛们要站成一排,但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 K 只牝牛。
请计算一共有多少种排队的方法,所有牡牛可以看成是相同的,所有牝牛也一样,答案对 5000011 取模。
【输入】
一行,输入两个整数 N 和 K。
【输出】
一个整数,表示排队的方法数。
【输入样例】
4 2
【输出样例】
6
【提示】
样例说明
6 种方法分别是:牝牝牝牝,牡牝牝牝,牝牡牝牝,牝牝牡牝,牝牝牝牡,牡牝牝牡。
(母母母母,公母母母,母公母母,母母公母,母母母公,公母母公)
数据范围与提示:
对于全部数据,1≤N≤105,0≤K<N。
由题意得要在两头公牛之间插入不少于规定数目的母牛,感觉上有点像隔板法,但是母牛的数量不一定,所以说似乎不太好做呢,我想了想也没想到该从何入手,所以就索性滚去看题接了,果然组合数学不是那么好想的呢,还不是因为我太菜了...
//参考题解:Cola
简单来说,就是枚举公牛的个数,然后算出此时最少需要多少头母牛(即(i-1)*k),那么此时就是在剩下的n-(i-1)*k个空位中放置这i头公牛,所以写成组合数的形式就是C(n-(i-1)*k,i)
但是注意要开long long哟,一开始我直接用int类型,最后一个点就RE了,后来我机智地把int改成定义long long(我真是太聪明了)就AC啦ㄟ(≧◇≦)ㄏ
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 int N,p=5000011,k,ans; 5 int mi(int a,int b) 6 { 7 int res=1; 8 while(b) 9 { 10 if(b&1)res=res*a%p; 11 a=a*a%p; 12 b>>=1; 13 } 14 return res; 15 } 16 int c(int n,int m) 17 { 18 if(n<m)return 0; 19 int a=1,b=1; 20 for(int i=n-m+1;i<=n;i++)a=a*i%p; 21 for(int i=2;i<=m;i++)b=b*i%p; 22 return a*mi(b,p-2)%p; 23 } 24 int l(int n,int m) 25 { 26 if(!m)return 1; 27 else return c(n%p,m%p)*l(n/p,m/p)%p; 28 } 29 signed main() 30 { 31 cin>>N>>k; 32 for(int i=0;i<=N;i++) 33 { 34 int j=N-(i-1)*k; 35 if(j<i)break; 36 ans=(ans+l(j,i))%p; 37 } 38 cout<<ans; 39 return 0; 40 }