【[SCOI2010]生成字串】
阿新 • • 發佈:2019-01-02
\(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\)
答案就是\(\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; }