卡特蘭數之括號匹配數問題(HDU5673)

摘抄百度百科
卡特蘭數又稱卡塔蘭數,英文名Catalan number,是組合數學中一個常出現在各種計數問題中出現的數列。由以比利時的數學家歐仁·查理·卡塔蘭 (1814–1894)命名,其前幾項爲 : 1,1,2,5,14,42,132,429,1430,4862,16796,58786,208012,742900,2674440,9694845,35357670,129644790,477638700,1767263190,6564120420,24466267020,91482563640,343059613650,1289904147324,4861946401452,...1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...
h(0)=1,h(1)=1h(0)=1,h(1)=1
卡特蘭數滿足:h(n)=i=0n1h(i)h(ni1)h(n)=\sum\limits_{i=0}^{n-1}h(i)\cdot h(n-i-1)
這個形式往往是我們運用卡特蘭數的精髓,通常化成這樣的遞推式,就可以運用卡特蘭數的另類公式解題了
另類公式:
h(n)=C(2n,n)n+1=C(2n,n)C(2n,n+1)h(n)=\frac{C(2n,n)}{n+1}=C(2n,n)-C(2n,n+1)
題意(HDU5673):機器人從原點開始走,每一步可以選擇不走,向左一步或向右一步,再原點時不能向右走,問走n步後回到原點的方案數是多少。
本題題解:
機器人要麼向左要麼向右或者不動,向左的次數肯定等於向右的次數,設向左的次數爲ii次,則向右的次數也爲ii次,不動的次數就爲n2in-2\cdot i,則不動的選擇爲C(n,n2i)C(n,n-2\cdot i)
現在剔除了不動點,剩下的都是要動的,分別爲向左ii次和向右ii次,因爲在原點時只能向右,所以從第一步開始,每一步累積的向左次數不能超過向右次數,否則就到原點左邊了
把向右走一步看成添加一個左括號,向左走看成添加一個右括號,則問題變成了,有ii對括號的合法括號序列爲多少個

h(n)h(n)爲有nn對括號的合法括號序列數,因爲每一個左括號唯一對應一個右括號,所以我們從左括號對應第幾個右括號枚舉起,如對應第一個右括號,則左邊()()括號內還有0對括號,相當於h(0)h(0),右邊剩下n1n-1對合法括號序列,相當於h(n1)h(n-1)
所以當一個左括號對應第一個右括號時有h(0)h(n1)h(0)\cdot h(n-1)個合法序列。
當第一個左括號對應第二個右括號時,左邊()()內還有一對括號的合法序列,所以爲h(1)h(1),右邊還剩n2n-2對括號,所以是h(n2)h(n-2)
所以當一個左括號對應第二個右括號時有h(1)h(n2)h(1)\cdot h(n-2)個合法序列。
後面枚舉是一樣的,可以發現這是一個遞推式,而且跟卡特蘭數的遞推式一模一樣。
所以有n2in-2i個不動點的合法情況是C(n,n2i)h(i)C(n,n-2\cdot i)\cdot h(i)
答案即爲i=0n/2C(n,n2i)h(i)\sum\limits_{i=0}^{n/2}C(n,n-2\cdot i)h(i)

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
const int MX=2e6+7;
const int mod=1e9+7;
using namespace std;
int p[MX],k[MX];
ll qpow(ll a,ll b,ll MOD=mod){for(ll ans=1;;a=a*a%MOD,b>>=1){if(b&1)ans=ans*a%MOD;if(!b)return ans;}}
ll inv(ll a,ll MOD=mod){return qpow(a,MOD-2,MOD);}
ll __gcm(ll a,ll b){return a*b/__gcd(a,b);}
ll A[MX],B[MX],C[MX];
int main()
{
  ios::sync_with_stdio(0),cin.tie(0);
  A[1]=1;
  A[0]=1;
  B[0]=1;
  B[1]=1;
  rep(i,2,MX-1)
  {
      A[i]=A[i-1]*i%mod;
      B[i]=inv(A[i])%mod;
      C[i]=B[i]*B[i]%mod*inv(i+1)%mod;
  }
  C[1]=inv(2);
  int T;
  cin>>T;
  while(T--){
    int n;
    cin>>n;
    ll sum=1;
    ll res=0;
    for(int i=1;i<=n/2;i++)
    {
        res=res+C[i]*B[n-2*i]%mod;
        if(res>=mod)res-=mod;
    }
    sum=sum+res*A[n]%mod;
    cout<<sum%mod<<endl;
  }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章