题解 P1641 【[SCOI2010]生成字符串】

题目链接

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 
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\n",(C(n + m,n) - C(n + m,n + 1) + mod) % mod);
    return 0;
}

你可能感兴趣的:(题解 P1641 【[SCOI2010]生成字符串】)