Solution [SCOI2010]生成字符串
题目大意:询问在(n)个(1)和(m)个(0)排列形成的字符串中,有多少个字符串任意前缀中(1)的个数不少于(0)的个数
卡特兰数
看到题面很容易想到卡特兰数,这里用与之类似的证明思路
首先(n)个(1),(m)个(0)组成的字符串有(C_{n + m}^{n})个(有(n+m)个位置,填了(n)个(1)自然(0)的位置就确定了)
我们减去不合法的字符串,存在任意前缀使得(0)数量大于(1)
假如有这种字符串的话,一定存在一个位置(2p+1 in [1,n+m]),使得前(2p+1)个数字里面有(p+1)个(0),(p)个(1),那么后面有(n-p)个(1),(m-p-1)个(0),对后面取反有(n-p)个(0),(m-p-1)个(1),所以我们得到了有(n+1)个(0),(m-1)个(1)的序列
同理,对于一个由(n+1)个(0),(m-1)个(1)组成的序列,我们也可以用同样的方法得到有(n)个(1),(m)个(0)的序列
也就是说这两种序列构成一个双射,即不合法序列的数量就是由(n+1)个(0),(m-1)个(1)组成的序列数量
所以答案(C_{n+m}^{n}-C_{n+m}^{n+1}),直接暴力求就好了
#include <cstdio>
using namespace std;
const int mod = 20100403;
typedef long long ll;
inline ll fac(ll x){
ll res = 1;
for(ll i = 1;i <= x;i++)res = (res * i) % mod;
return res;
}
inline ll qpow(ll a,ll b){
a %= mod;
ll base = a,res = 1;
while(b){
if(b & 1)res = (res * base) % mod;
base = (base * base) % mod;
b >>= 1;
}
return res;
}
inline ll inv(ll x){return qpow(x,mod - 2);}
inline ll mul(ll a,ll b){return (a * b) % mod;}
inline ll C(ll n,ll m){return m > n ? 0 : mul(mul(fac(n),inv(fac(m))),inv(fac(n - m)));}
int n,m;
int main(){
scanf("%d %d",&n,&m);
printf("%lld
",(C(n + m,n) - C(n + m,n + 1) + mod) % mod);
return 0;
}