3398: [Usaco2009 Feb]Bullcow 牡牛和牝牛
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 440 Solved: 301
Description
约翰要带N(1≤N≤100000)只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛.牛们要站成一排.但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有K(O≤K<N)只牝牛.
请计算一共有多少种排队的方法.所有牡牛可以看成是相同的,所有牝牛也一样.答案对5000011取模
Input
一行,输入两个整数N和K.
Output
一个整数,表示排队的方法数.
Sample Input
4 2
Sample Output
6
样例说明
6种方法分别是:牝牝牝牝,牡牝牝牝,牝牡牝牝,牝牝牡牝,牝牝牝牡,牡牝牝牡
解析:
网上一大堆题解都是动态规划,但我用的是组合数。
枚举牡牛的数量m,将总牛数减去至少需要的牝牛数量后记为n,则每种数量的答案就为C(n,m),答案就是把合法答案加起来即可。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=5000011;
int n,k,ans;
inline int ksm(int a,int b)
{
int ans = 1;
a = a % mod;
while(b)
{
if(b&1) ans = (ans * a) % mod;
b >>= 1;
a = (a * a) %mod;
}
return ans % mod;
}
inline int C(int n,int m)
{
if(m > n) return 0;
int a=1,b=1;
for(register int i=n-m+1;i<=n;i++) a = a * i % mod;
for(register int i=2;i<=m;i++) b = b * i % mod;
return a * ksm(b,mod-2) % mod;
}
inline int Lucas(int n,int m)
{
if(!m) return 1;
else return (C(n % mod , m % mod) % mod * Lucas(n / mod , m / mod) % mod) % mod;
}
signed main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<=n;i++)
{
int j=n-(i-1)*k;
if(j<i) break;
ans=(ans+Lucas(j,i))%mod;
}
cout<<ans<<"\n";
return 0;
}