zoukankan      html  css  js  c++  java
  • 卡特兰数(catalan)总结

    卡特兰数的公式

    递推公式1:$f(n)=sum limits_{i=0}^{n-1}f(i)*f(n-i-1)$

    递推公式2:$f(n)=frac{f(n-1)*(4*n-2)}{n+1}$

    组合公式1:$f(n)=frac{C_{2n}^{n}}{n+1}$

    组合公式2:$f(n)=C_{2n}^{n}-C_{2n}^{n-1}$

    关于卡特兰数的题目

    1. 有限制的网格方案数   eg网格

    利用组合数的思想:

    对于长N宽M的网格(下图2),方案数为 $C_{n+m}^{m}-C_{n+m}^{m-1}$

    理解:走到(n,m)这个点总共要走n+m步,其中有m步一定是向上的,所以$C_{n+m}^{m}$这是所有情况

       但有不合法的情况,且不合法的一定经过绿线,将原图形沿其翻折,相当于走到c点,此时总n+m步不变,但只有m-1步是向右的

       所以$C_{n+m}^{m-1}$是不合法的

                                                                  (借用kaola学长的图)

    对于N×N的网格就是卡特兰数了,如图一

     本题先将式子化简,然后将其分解质因数,消去除法,最后乘上每个质数的个数次方就好

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 using namespace std;
     6 int n,m,num,p[10005],v[10005];
     7 int sum[10005];
     8 void prime(int x)
     9 {
    10     for(int i=2;i<=x;i++)
    11     {
    12         if(!v[i])    {v[i]=i;p[++num]=i;}
    13         for(int j=1;j<=num;j++){
    14             if(p[j]>v[i]||i*p[j]>x) continue;
    15             v[i*p[j]]=p[j];
    16         }
    17     }
    18 }
    19 int len=1,ans[100000001];
    20 void mul(int x)
    21 {
    22     int k=0;
    23     for(int i=1;i<=len;i++)
    24     {
    25         ans[i]=ans[i]*x+k;
    26         k=ans[i]/10;
    27         ans[i]%=10;
    28         if(k>0&&i==len)  len++;
    29     }
    30 }
    31 int main()
    32 {
    33     ans[1]=1;
    34     scanf("%d%d",&n,&m);
    35     prime(n+m+1);
    36     int t=n+1-m;
    37     while(t>1)
    38     {
    39         sum[v[t]]++;
    40         t/=v[t];
    41     }
    42     for(int i=n+m;i>=n+2;i--)
    43     {
    44         t=i;
    45         while(t>1)
    46         {
    47             sum[v[t]]++;
    48             t/=v[t];
    49         }
    50     }
    51     for(int i=2;i<=m;i++)
    52     {
    53         t=i;
    54         while(t>1)
    55         {
    56             sum[v[t]]--;
    57             t/=v[t];
    58         }
    59     }
    60     for(int i=1;i<=num;i++)
    61         for(int j=1;j<=sum[p[i]];j++)
    62             mul(p[i]);
    63     for(int i=len;i>=1;i--)
    64         printf("%d",ans[i]);
    65     puts("");
    66 }
    View Code

     2.有趣的数列

    其实这个也可以理解为上一个网格,将偶数位记为向右走一步,奇数位记为向上走一步,,偶数位之和大于奇数位之和,就是不能越过绿线

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 #define ll  long long
     6 using namespace std;
     7 const int maxn=2000005;
     8 int n,mod,num;
     9 ll p[maxn];int v[maxn];
    10 ll sum[maxn];
    11 void prime(int x)
    12 {
    13     for(int i=2;i<=x;i++)
    14     {
    15         if(!v[i])    {v[i]=i;p[++num]=i;}
    16         for(int j=1;j<=num;j++){
    17             if(p[j]>v[i]||i*p[j]>x) break;
    18             v[i*p[j]]=p[j];
    19         }
    20     }
    21 }
    22 ll qpow(int a,int b)
    23 {
    24     ll ans=1;
    25     while(b)
    26     {
    27         if(b&1)  ans=ans*a%mod;
    28         a=a*a%mod;
    29         b>>=1;
    30     }
    31     return ans%mod;
    32 }
    33 int  main()
    34 {
    35     scanf("%d%d",&n,&mod);
    36     prime(2*n+1);
    37     for(int i=2*n;i>=n+2;i--)
    38     {
    39         int t=i;
    40         while(t>1)
    41         {
    42             sum[v[t]]++;
    43             t/=v[t];
    44         }
    45     }
    46     for(int i=1;i<=n;i++)
    47     {
    48         int t=i;
    49         while(t>1)
    50         {
    51             sum[v[t]]--;
    52             t/=v[t];
    53         }
    54     }
    55     ll ans=1;
    56     for(int i=1;i<=num;i++)
    57         if(sum[p[i]])
    58             ans=ans*qpow(p[i],sum[p[i]])%mod;
    59     printf("%lld
    ",ans);
    60 }
    View Code

    3.树屋阶梯

     我们不妨手模样例,若扣去左下角直角所在矩形,

    图一和图四的方案数为右面的2块的方案数×上面的0块的方案数,即为$f(3)+=f(2)*f(0)$

    同理图二和图五为$f(3)+=f(0)*f(2)$   图三为$f(3)+=f(1)*f(1)$

    由此可得  $f(n)=sum limits_{i=0}^{n-1}f(i)*f(n-i-1)$  卡特兰数公式1

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<cmath>
     5 using namespace std;
     6 int n,num,p[10005],v[10005];
     7 int sum[10005];
     8 void prime(int x)
     9 {
    10     for(int i=2;i<=x;i++)
    11     {
    12         if(!v[i])    {v[i]=i;p[++num]=i;}
    13         for(int j=1;j<=num;j++){
    14             if(p[j]>v[i]||i*p[j]>x) break;
    15             v[i*p[j]]=p[j];
    16         }
    17     }
    18 }
    19 int len=1,ans[10000001];
    20 void mul(int x)
    21 {
    22     int k=0;
    23     for(int i=1;i<=len;i++)
    24     {
    25         ans[i]=ans[i]*x+k;
    26         k=ans[i]/10;
    27         ans[i]%=10;
    28         if(k>0&&i==len)  len++;
    29     }
    30 }
    31 int main()
    32 {
    33     ans[1]=1;
    34     scanf("%d",&n);
    35     prime(2*n+1);
    36     for(int i=2*n;i>=n+2;i--)
    37     {
    38         int t=i;
    39         while(t>1)
    40         {
    41             sum[v[t]]++;
    42             t/=v[t];
    43         }
    44     }
    45     for(int i=1;i<=n;i++)
    46     {
    47         int t=i;
    48         while(t>1)
    49         {
    50             sum[v[t]]--;
    51             t/=v[t];
    52         }
    53     }
    54     for(int i=1;i<=num;i++)
    55         for(int j=1;j<=sum[p[i]];j++)
    56             mul(p[i]);
    57     for(int i=len;i>=1;i--)
    58         printf("%d",ans[i]);
    59     puts("");
    60 }
    View Code

    关于卡特兰数的其他应用

    1.出栈入栈问题:1,2,~n个数经过一个栈,合法的出栈序列$Cat(n)$

      (引用学长的课件)出栈次序是卡特兰数的一个应用。 我们将入栈视为+1,出栈视为-1,则限制条件为在任意位置前缀和不小于0 。 我们讨论这个问题与卡特兰数有什么关系。 为了方便,我们按入栈的先后顺序将各个元素由1到n编号。 假设最后一个出栈的数为k。 则在k入栈之前,比k小的数一定全部出栈,所以这部分方案数为h(k-1)。 在k入栈之后,比k大的数在k入栈之后入栈,在k出栈之前出栈,所以这部分的方案数为h(n-k)。 这两部分互不干扰,则方案数为h(k-1)*h(n-k) 枚举k,得到的公式就是卡特兰数的递推公式。

    2.左括号与右括号的匹配问题:n个左括号和n个右括号组成的合法括号序列$Cat(n)$

      跟入栈出栈的理解是一样的

    3.n个节点构成的二叉树的方案数为$Cat(n)$

      假设左子树有$i$个节点,右子树有$n-i-1$个节点,i从0到n-1,根据乘法原理

    可得公式1$f(n)=sum limits_{i=0}^{n-1}f(i)*f(n-i-1)$

    愿你在迷茫时,记起自己的珍贵。
  • 相关阅读:
    Codeforces Round #433 (Div. 1, based on Olympiad of Metropolises) B. Jury Meeting 贪心
    Codeforces Round #433 (Div. 1, based on Olympiad of Metropolises) A. Planning 优先队列
    forms组件的渲染错误信息,全局和局部钩子函数,cookie,session
    ajax处理urlencoded的装饰器,ajax上传文件,分页器组件,forms组件
    初识ajax
    django之手动创建第三张表 常用字段
    django之分组,聚合,F.Q.查询
    django的多表操作
    模板的导入和继承 单标操作
    day80 django模版学习
  • 原文地址:https://www.cnblogs.com/casun547/p/11222539.html
Copyright © 2011-2022 走看看