卡特兰数之括号匹配数问题(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, ... 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 ) = 1 h(0)=1,h(1)=1 h(0)=1,h(1)=1
卡特兰数满足: h ( n ) = ∑ i = 0 n − 1 h ( i ) ⋅ h ( n − i − 1 ) h(n)=\sum\limits_{i=0}^{n-1}h(i)\cdot h(n-i-1) h(n)=i=0n1h(i)h(ni1)
这个形式往往是我们运用卡特兰数的精髓,通常化成这样的递推式,就可以运用卡特兰数的另类公式解题了
另类公式:
h ( n ) = C ( 2 n , n ) n + 1 = C ( 2 n , n ) − C ( 2 n , n + 1 ) h(n)=\frac{C(2n,n)}{n+1}=C(2n,n)-C(2n,n+1) h(n)=n+1C(2n,n)=C(2n,n)C(2n,n+1)
题意(HDU5673):机器人从原点开始走,每一步可以选择不走,向左一步或向右一步,再原点时不能向右走,问走n步后回到原点的方案数是多少。
本题题解:
机器人要么向左要么向右或者不动,向左的次数肯定等于向右的次数,设向左的次数为 i i i次,则向右的次数也为 i i i次,不动的次数就为 n − 2 ⋅ i n-2\cdot i n2i,则不动的选择为 C ( n , n − 2 ⋅ i ) C(n,n-2\cdot i) C(n,n2i)
现在剔除了不动点,剩下的都是要动的,分别为向左 i i i次和向右 i i i次,因为在原点时只能向右,所以从第一步开始,每一步累积的向左次数不能超过向右次数,否则就到原点左边了
把向右走一步看成添加一个左括号,向左走看成添加一个右括号,则问题变成了,有 i i i对括号的合法括号序列为多少个

h ( n ) h(n) h(n)为有 n n n对括号的合法括号序列数,因为每一个左括号唯一对应一个右括号,所以我们从左括号对应第几个右括号枚举起,如对应第一个右括号,则左边 ( ) () ()括号内还有0对括号,相当于 h ( 0 ) h(0) h(0),右边剩下 n − 1 n-1 n1对合法括号序列,相当于 h ( n − 1 ) h(n-1) h(n1)
所以当一个左括号对应第一个右括号时有 h ( 0 ) ⋅ h ( n − 1 ) h(0)\cdot h(n-1) h(0)h(n1)个合法序列。
当第一个左括号对应第二个右括号时,左边 ( ) () ()内还有一对括号的合法序列,所以为 h ( 1 ) h(1) h(1),右边还剩 n − 2 n-2 n2对括号,所以是 h ( n − 2 ) h(n-2) h(n2)
所以当一个左括号对应第二个右括号时有 h ( 1 ) ⋅ h ( n − 2 ) h(1)\cdot h(n-2) h(1)h(n2)个合法序列。
后面枚举是一样的,可以发现这是一个递推式,而且跟卡特兰数的递推式一模一样。
所以有 n − 2 i n-2i n2i个不动点的合法情况是 C ( n , n − 2 ⋅ i ) ⋅ h ( i ) C(n,n-2\cdot i)\cdot h(i) C(n,n2i)h(i)
答案即为 ∑ i = 0 n / 2 C ( n , n − 2 ⋅ i ) h ( i ) \sum\limits_{i=0}^{n/2}C(n,n-2\cdot i)h(i) i=0n/2C(n,n2i)h(i)

#include
#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;
  }
}

你可能感兴趣的:(数学,卡特兰数)