【Usaco 2009 Feb】Bullcow 牡牛和牝牛

【题目】

传送门

Description

约翰要带 n ( 1 n 100000 ) n(1≤n≤100000) 只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛。牛们要站成一排。但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 k ( 0 k < n ) k(0≤k<n) 只牝牛。

请计算一共有多少种排队的方法。所有牡牛可以看成是相同的,所有牝牛也一样。答案对 5000011 5000011 取模。

Input

一行,输入两个整数 n n k k

Output

一个整数,表示排队的方法数。

Sample Input

4 2

Sample Output

扫描二维码关注公众号,回复: 4706706 查看本文章

6

HINT

6 6 种方法分别是:牝牝牝牝,牡牝牝牝,牝牡牝牝,牝牝牡牝,牝牝牝牡,牡牝牝牡


【分析】

牡( m u ˇ )牛,公牛的意思,牝( p ı ˋ n pìn )牛,母牛的意思

好啦这不是这道题的重点,重点是这道题的算法

不难发现,如果有 x x 头牡牛,一定会有 ( x 1 ) k (x-1)\cdot k 头牝牛,也就是说牡牛只能在剩下的 n ( x 1 ) k n-(x-1)\cdot k 个位置上选,方案数就是 C n ( x 1 ) k                x C^{\;\;\;\;\;\;\;x}_{n-(x-1)\cdot k}

那么循环枚举有多少个牡牛,按公式计算答案后累加,到 x > n ( x 1 ) k x>n-(x-1)\cdot k 退出就可以了

最后吐槽一下,数据范围是不是有误啊,数组开小导致 WA 了好久


【代码】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000005
#define Mod 5000011
using namespace std;
int fac[N],inv[N];
int Power(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1)
		  ans=1ll*ans*a%Mod;
		a=1ll*a*a%Mod;
		b>>=1;
	}
	return ans;
}
void prework()
{
	int i;
	fac[0]=fac[1]=1;
	for(i=2;i<N;++i)  fac[i]=1ll*fac[i-1]*i%Mod;
	inv[N-1]=Power(fac[N-1],Mod-2);
	for(i=N-2;~i;--i)  inv[i]=1ll*inv[i+1]*(i+1)%Mod;
}
int C(int n,int m)
{
	return 1ll*fac[n]*inv[m]%Mod*inv[n-m]%Mod;
}
int main()
{
	prework();
	int n,k,i,num,ans=1;
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;++i)
	{
		num=n-(i-1)*k;
		if(i>num)  break;
		ans=(ans+C(num,i))%Mod;
	}
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/85371155