卡特兰数小总结

参考自:大佬1大佬2.

问题一: 括号匹配问题

n n n个左括号, n n n个右括号,要求左括号和右括号匹配,总方案数。
即中间不能出现前缀的右括号数量大于左括号。

考虑随机放的方案: C ( n , 2 n ) C(n,2 n) C(n,2n)
考虑不合法的情况,如果我们把第一个不合法的位置设为 k k k,将 [ 1 , k ] [1,k] [1,k]翻转。
得到的左括号为 n + 1 n+1 n+1
那么对于一个左括号为 n + 1 n+1 n+1,右括号为 n − 1 n-1 n1的随机放的方案能不能转换成原来的不合法方案呢。
如果左括号是 1 1 1,右括号是 − 1 -1 1,对于 − 1   1   1   1 -1\ 1\ 1\ 1 1 1 1 1,将前缀 1 1 1多的第一个位置开始往前翻转就可以了。
不合法方案数为 C ( n + 1 , 2 n ) C(n+1,2n) C(n+1,2n)

合法方案数为: C ( n , 2 n ) − C ( n + 1 , 2 n ) C(n,2n)-C(n+1,2n) C(n,2n)C(n+1,2n)

类似的问题:

1、 D c k y   w o r d s Dcky\ words Dcky words n n n X X X, n n n Y Y Y,前缀满足 X ≥ Y X\geq Y XY
2、 2 n 2n 2n个人买票,只有 50 50 50 100 100 100,售票处一开始没钱,一张票 50 50 50,求每个人有票不会发生无法找钱的情况的方案数。
3、标准 Y o u n g Young Young表, 2 ∗ n 2*n 2n的矩阵,填 1 − 2 n 1-2n 12n的数,要求每一列和每一排都递增

这道题我们令第一行为左括号,第二行为右括号,首先如果分好了第几行放法是唯一的,所以只要保证分的过程中,放在第二行的有足够多的数使得放在第一行的比他们大。
知乎大佬1的图
(此图是大佬的图)
4、不相交的弦:一个圆上 2 n 2n 2n个点,连线,得到 n n n条不相交的线。
从某个点开始,弦的第一个点为 ( ( (,第二个点为 ) ) )。即可。
在这里插入图片描述
(此图也是大佬的图)
做法二就是:转换成卡特兰数通用形式—— ∑ f ( i ) f ( n − i ) \sum f(i)f(n-i) f(i)f(ni),枚举某条边的分割。

问题二:出栈序列

入栈序列为 1   2   3   . . .   n 1\ 2\ 3\ ...\ n 1 2 3 ... n,求方案数。
其实可以等价于括号匹配,因为要求先入才有出,入的数量大于等于出的数量

类似的问题:

1、 n n n个斜向上和 n n n个斜向下,画群峰的方案数[不能掉到水平线下]
做法一:括号匹配
做法二:考虑第一个回到水平点的位置,分割成子问题。
2、不穿越对角线的格路问题(从 ( 0 , 0 ) (0,0) (0,0) ( n , m ) (n,m) (n,m))
做法一:括号匹配
做法二:可以把其转个 135 135 135度变成群峰问题。
3、满二叉树的种数
前序遍历:通过类似 d f s dfs dfs,转换成出栈序列
中序遍历:分成子问题。
4、不出现"312"的全排列
一个长度为n的排列a,只要满足 i < j < k i<j<k i<j<k a j < a k < a i aj<ak<ai aj<ak<ai就称这个排列为 312 312 312排列。
312 312 312是长度为 3 3 3不可能出现的出栈序列,也就是该问题可以变成出栈序列。
同理 213 213 213 123 123 123都是一样的,虽然没有实际意义,但是和 312 312 312在答案上是等价的。
** 5、矩阵的阶梯划分**
给定一个阶梯,划分成多个矩阵。
见此处。

卡特兰数

f ( n ) = C 2 n n n + 1 = C 2 n n − C 2 n n + 1 = ∑ i = 0 n − 1 f ( i ) ∗ ( n − i − 1 ) f(n)=\frac{C^n_{2n}}{n+1}=C^n_{2n}-C^{n+1}_{2n}=\sum\limits_{i=0}^{n-1}f(i)*(n-i-1) f(n)=n+1C2nn=C2nnC2nn+1=i=0n1f(i)(ni1)

例题

洛谷1641 生成字符串
括号匹配 n n n m m m,保证 n ≥ m n\geq m nm
傻逼才不会的题,所以我是傻逼。等价于之前的问题,之前是把第一个不满足条件翻转,此题同理,反转后, 1 1 1的数量会多 1 1 1
所以答案是 C ( n + m , n ) − C ( n + m , n + 1 ) C(n+m,n)-C(n+m,n+1) C(n+m,n)C(n+m,n+1)
洛谷P2532 树屋阶梯
任意大的 n n n个矩形搭建阶梯,每次差一格。
考虑到每个拐角一定有一个且一个矩形包含,每个矩形只有一个。
并且对于左下角必然被某个矩形包含,枚举被哪个包含了,就可以分成子问题了。

如果是最上面的拐角就是: f ( 0 ) ∗ ( f n − 1 ) f(0)*(fn-1) f(0)(fn1),第二个就是: f ( 1 ) ∗ f ( n − 2 ) f(1)*f(n-2) f(1)f(n2)…以此类推。
即卡特兰数。
在这里插入图片描述
洛谷题解里的图(盗用)
洛谷P3200 有趣的数列
2 n 2n 2n个数放到数列中,保证奇数项递增,偶数项递增,相邻:奇数 < < <偶数

可以发现,前面要小一点,后面才放的下。
对于每个偶数项,大于前面所有的数, S i ≥ 2 ∗ i S_i\geq 2*i Si2i,可以发现从 1 − 2 n 1-2n 12n,到 2 ∗ i 2*i 2i,至多 i i i个偶数项。
也就是说,保证偶数项小于等于奇数项即可。
此题还要求非质数取模,晒个板子

#include<bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn = 2e6+510;
const int mod = 1e9+7;

struct C_not_prime_mod{
    bool prime[maxn];
    int p[maxn];
    int cnt;

    void isprime(){
        cnt = 0;
        memset(prime,true,sizeof(prime));
        for(int i=2; i<maxn; i++){
            if(!prime[i])continue;
            p[cnt++] = i;
            for(int j=i+i; j<maxn; j+=i)prime[j] = false;
        }
    }

    ll quick_mod(ll a,ll b,ll m){
        ll ans = 1;
        a %= m;
        while(b){
            if(b & 1){
                ans = ans * a % m;
                b--;
            }
            b >>= 1;
            a = a * a % m;
        }
        return ans;
    }

    ll Work(ll n,ll p){
         ll ans = 0;
         while(n){
             ans += n / p;
             n /= p;
         }
         return ans;
     }

    ll Solve(ll n,ll m,ll P){
        ll ans = 1;
        for(int i=0; i<cnt && p[i]<=n; i++){
            ll x = Work(n, p[i]);
            ll y = Work(n - m, p[i]);
            ll z = Work(m, p[i]);
            x -= (y + z);
            ans *= quick_mod(p[i],x,P);
            ans %= P;
        }
        return ans;
    }
}cnpm;

int main(){
    cnpm.isprime();
    ll n,p;cin>>n>>p;
    ll ans=(cnpm.Solve(2*n,n,p)-cnpm.Solve(2*n,n-1,p))%p+p;
    cout<<ans%p<<endl;
}

某场 g y m gym gym J J J

题意

现有一颗树,每个结点上有个标号,并且满足如下性质,子节点的标号值不小于父亲结点。
现在给出这棵树中序遍历的标号序列。
问有多少棵树满足以上条件。

题解

首先找到最小值,如果只有一个就其作为根,否则其先做出一棵树。
剩余部分插到这棵树上。
在这里插入图片描述
显然他们是连续的,否则根最小的性质不满足。
最小值分成了多个区间,插进去即可。
而最小值构成的这个树,显然是卡特兰数。

写法就是枚举每个点的贡献,即从大到小,一旦出现比自己小的数,就重新划分区间。
例如 3 3 3,这里的 3 3 3一定是被分了 3 3 3个,而 2 2 2也是 3 3 3个。
对于每个数每个区间都是一颗连续的树,所以直接卡特兰数相乘即可。

递归的方法复杂度是不够的。要求 O n On On,判断有没有更小的时候用 r m q rmq rmq

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值