[ABC205E] White and Black Balls 题解

发布时间 2023-06-05 13:31:06作者: TKXZ133

White and Black Balls

题目大意

\(n\) 个白球,\(m\) 个黑球排成一列,要求满足 \(\forall i\in[1,n+m],w_i\le b_i+k\),问存在多少种排法。

其中 \(w_i\) 表示第 \(i\) 个球前的白球数量,\(b_i\) 表示第 \(i\) 个球前的黑球数量。

思路分析

我们可以将一种排法映射成一条从 \((0,0)\)\((m,n)\) 的路径。具体的说,从 \((0,0)\) 开始,如果当前球是白球,那么向上移动一个单位长度;如果是黑球,那么向右移动一个单位长度,到达 \((m,n)\) 结束。

容易发现,路径条数为 \(C_{n+m}^m\),但其中包含不合法的情况,需要排除。

如图,我们发现,如果一条路径始终位于直线 \(y=x+k\) 下方,那么这条路径就是合法的。换而言之,如果一条路径与直线 \(y=x+k+1\) 有交点,那么这条路径不合法。

对于不合法的路径,我们将最右端的交点的左半部分沿 \(y=x+k+1\) 翻转,得到一条新的从 \((-k-1,k+1)\)\((m,n)\) 的路径,显然所有的不合法路径可以通过这种办法与从 \((-k-1,k+1)\)\((m,n)\) 的路径一一对应。而这样的路径条数为 \(C_{n+m}^{m+k+1}\)

因此,最后的答案就是 \(C_{n+m}^m-C_{n+m}^{m+k+1}\)

注意特判 \(n>m+k\) 的情况。

代码

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;
const int N=2000100,L=2000000,mod=1000000007;
#define int long long

int n,m,k;
int fac[N],inv[N];

int q_pow(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return res;
}

int C(int a,int b){//逆元法直接计算
    return ((fac[a]*inv[b]%mod)*inv[a-b])%mod;
}

signed main(){
    scanf("%lld%lld%lld",&n,&m,&k);
    fac[0]=1;
    for(int i=1;i<=L;i++) fac[i]=fac[i-1]*i%mod;
    inv[L]=q_pow(fac[L],mod-2);
    for(int i=L;i>=1;i--) inv[i-1]=inv[i]*i%mod;//预处理逆元
    if(n>m+k){cout<<"0\n";return 0;}//特判
    int ans=(C(n+m,m)-C(n+m,m+k+1)+mod)%mod;//计算答案,可能出负数,需再模一遍
    cout<<ans<<'\n';
    return 0;
}