原题来自:USACO 2009 Feb. Silver
牡 mǔ,畜父也。牝 pìn,畜母也。 ——《说文解字》
约翰要带 n 只牛去参加集会里的展示活动,这些牛可以是牡牛,也可以是牝牛。牛们要站成一排,但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 k只牝牛。
请计算一共有多少种排队的方法,所有牡牛可以看成是相同的,所有牝牛也一样,答案对 5000011 取模。
输入格式
一行,输入两个整数 n和 k。
(1<=n<=1e5,0<k<n)
输出格式
一个整数,表示排队的方法数。
样例输入
4 2
样例输出
6
通过枚举公牛的数量i,可以求出公牛间的空隙数为n-1,进而求出所需母牛的数量(n-1)* k,再求出实际存在的公牛的数量n-(i-1)* k,如果实际存在的数量大于枚举量,说明容纳不了这么多
还有一个问题,因为模数比范围大,所以不需要lucas,仅用排列组合就行了(感觉lucas这个东西跟快读快写似的,多数是为了存__int128,而不是加速)
还有一个问题,要算上没有公牛的情况,很简单,+1就行,如果想从0开始枚举记得开大点数组,因为n+k>n
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int p=5000011;
typedef long long ll;
ll n,k;
ll sum;
ll fact[120000],inv[120002];
ll C(ll n,ll m,ll p){
return (fact[n]*inv[m]%p*inv[n-m]%p)%p;
}
ll qpow(ll n,ll m,ll p){
ll ans=1;
while(m){
if(m&1) ans=ans*n%p;
n=n*n%p;
m>>=1;
}
return ans;
}
int main(){
cin>>n>>k;
fact[0]=1;inv[0]=1;
for(int i=1;i<=n;i++){
fact[i]=fact[i-1]*i%p;
inv[i]=qpow(fact[i],p-2,p);
}
for(int i=1;i<=n;i++){
int j=n-(i-1)*k;
if(j<i) continue;
sum+=C(j,i,p);
sum%=p;
}
cout<<sum+1;
}