1. 程式人生 > >【[SCOI2010]生成字串】

【[SCOI2010]生成字串】

\(n=m\)時候經典的卡特蘭

\(n!=m\)呢,還是按照卡特蘭的方式來推

首先總情況數就是\(\binom{n+m}{n}\),在\(n+m\)個裡選擇\(n\)\(1\)

顯然有不合法的情況,減掉它們

對於一種不合法的情況,必然存在一個字首\(0\)的個數比\(1\)\(1\)

我們考慮構造出一個由\(n+1\)\(1\)\(m-1\)\(0\)組成的序列,其必然存在一個字首使得\(1\)的個數比\(0\)\(1\)

於是就能一一對應了

也可以這樣理解,對於每一個不合法的情況,找到第一個不合法的字首,將其取反,之後就會得到一個\(n+1\)\(1\)\(m-1\)

\(0\)組成的字串,還是可以一一對應

答案就是\(\binom{n+m}{n}-\binom{n+m}{n+1}\)

程式碼

#include<iostream>
#include<cstring>
#include<cstdio>
#define LL long long
#define re register
#define maxn 1000005
const LL mod=20100403;
LL n,m,fac[maxn*2];
inline int read()
{
    char c=getchar();
    int x=0;
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-48,c=getchar();
    return x;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b) return x=1,y=0,a;
    LL r=exgcd(b,a%b,y,x);
    y-=a/b*x;
    return r;
}
inline LL inv(LL a)
{
    LL x,y;
    LL r=exgcd(a,mod,x,y);
    return (x%mod+mod)%mod;
}
inline LL C(LL n,LL m)
{
    if(m>n) return 0;
    return (fac[n])*inv(fac[m]*fac[n-m]%mod)%mod;
}
int main()
{
    n=read(),m=read();
    fac[0]=1;
    for(re int i=1;i<=n+m;i++) fac[i]=(fac[i-1]*i)%mod;
    printf("%lld\n",(C(n+m,n)-C(n+m,n+1)+mod)%mod);
    return 0; 
}