[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);
}
posted @ 2023-07-25 14:13  Zimo_666  阅读(18)  评论(0编辑  收藏  举报