[ABC205E] White and Black Balls
[ABC205E] White and Black Balls
题意
给出 \(n\) 个白球,\(m\) 个黑球及一个常数 \(k\),问有多少种排列使得 \(\forall i\in[1,n+m],w_i\le b_i+k\),其中 \(w_i\) 表示在排列的第 \(i\) 个球以及它之前的白球个数,\(b_i\) 表示在排列的第 \(i\) 个球以及它之前的黑球个数。
分析
我们转换一下题目条件可以得 \(b_{i}-w_{i}≥-k\)。而后我们可以把问题转化为从数轴原点出发,要求向右走 \(m\) 步,向左走 \(n\) 步,并且不越过 \(-k\)。我们不考虑限制条件那么所有的操作方案数为 \(C_{n+m}^n\)。
而后我们考虑这个不越过 \(-k\) 的限制条件。显然有所有不合法操作都会抵达 \(-k-1\)。那么我们把所有这一时刻后的不合法操作以 \(-k-1\) 为对称轴取反。则有最后我们经过一些操作,由原来的终点 \(n-m\) 变为 \(n-m-2(k+1)\)。我们设向右走 \(R\) 步且为正贡献1,向左走 \(L\) 步且为负贡献1。
则有二元一次方程组 \(L+R=n+m,R-L=n-m-2(k+1)\)。
那么我们解得 \(L=m+k+1,R=n-k-1\)。则有不合法路径数 \(C_{n+m}^{m+k+1}\)。
于是答案为 \(C_{n+m}^{n}-C{n+m}^{m+k+1}\)。我们可以使用快速幂+逆元求算组合数。实现如下。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
struct node{
const int mod=1e9+7;
int inv[2000005],fac[2000005];
int qpow(int shu,int cifang){
int ans=1;int k=cifang;
while(k){
if(k&1){ans=ans*shu%mod;ans%=mod;shu=shu*shu%mod;shu%=mod;}
else{shu=shu*shu%mod;shu%=mod;}
k>>=1;
}
return ans%mod;
}
void init(int len){
fac[0]=1;
for(int i=1;i<=len;i++) fac[i]=fac[i-1]*i%mod;
inv[len]=qpow(fac[len],mod-2);
// printf("%lld",inv[n+m]);
for(int i=len;i;i--){
inv[i-1]=inv[i]*(i)%mod;
}
}
int C(int n,int m){
return fac[n]%mod*inv[m]%mod*inv[n-m]%mod;
}
}lg_get;
int k;
signed main(){
cin>>n>>m>>k;
lg_get.init(2000000);
if(n>m+k) return printf("0"),0;
int ans=lg_get.C(n + m, m) - lg_get.C(n + m, m+k+1);
ans+=lg_get.mod;
ans%=lg_get.mod;
printf("%lld",ans);
}