BZOJ 1856 [Scoi2010]字符串 - 卡特蘭數推廣

先mark一下別人博客:

卡特蘭數的推導(用01序列推導的,過於抽象):
http://blog.csdn.net/youwuwei2012/article/details/38904839
(好像還有嚴格證明,只不過看不懂QAQ)

然後以這種推導的思路進行更易於理解的證明:

referring to:
http://www.cnblogs.com/jianglangcaijin/p/3443689.html
http://blog.csdn.net/wzq_qwq/article/details/48706151


(圖源:wzq_QwQ,圖爲推廣的模型)
對於卡特蘭數的基礎模型,進棧和出棧的次數相等且爲一定值2n,其中進棧次數爲n且在任意時刻進棧次數不小於出棧次數。考慮一個座標軸的模型,記每一次操作爲右移一格,出棧下移,進棧上移,於是縱座標代表棧內元素個數y,且y恆爲非負整數。根據卡特蘭數的定義,從(0,0)開始移動,終止於(2n,0)點,由此操作數共有Cn2n ,然而其中包含不合法的情況。曲線不能到達直線y=-1,現在考慮不合法的情況的個數,即將(0,0)沿直線y=-1對稱,從(-2,0)到達(2n,0)的種數,共有Cn+12n 。二者相減即爲合法情況總數,公式爲:h(n)=Cn2nCn+12n


綜上,卡特蘭數的公式爲:
h(n)=Cn2nn+1=Cn2nCn+12n

將證明推廣,進棧元素設爲m(m>=n),於是同理可得推廣後的卡特蘭數公式:

h(n)=Cnn+mCn+1n+m

此題按此公式,拿逆元求一下就好了。一定不能寫錯exgcd!!!

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

using namespace std;

const int mod=20100403;

int n,m;

int exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    int res=exgcd(b,a%b,x,y);
    int temp=x;
    x=y;
    y=temp-y*(a/b);
    return res;
}
int inverse(int a)
{
    int x,y;
    exgcd(a,mod,x,y);
    return (x%mod+mod)%mod;
}
int C(int m,int n)
{
    int res=1;
    for(int i=n-m+1;i<=n;i++)
        res=1LL*res*i%mod;
    for(int i=2;i<=m;i++)
        res=1LL*res*inverse(i)%mod;
    return res;
}
int main()
{
    scanf("%d%d",&n,&m);
    cout<<((C(n,m+n)-C(n+1,m+n))%mod+mod)%mod;
    return 0;
} 
發佈了112 篇原創文章 · 獲贊 4 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章