Chgtaxihe's blog Chgtaxihe's blog
首页
练习
算法学习
读书笔记
小玩意

Chgtaxihe

首页
练习
算法学习
读书笔记
小玩意
  • 训练补题
  • Codeforces 刷题计划
  • 概率dp练习
  • dp专题练习
  • 数论练习
  • 搜索专题练习
  • 图论练习
  • 基础字符串练习
  • AtCoder练习
  • 题解们
  • solutions

    • POJ-3468
    • Gym102501J题解
      • Gym102501J
        • 子问题:n个节点的二叉树有多少种形态
        • 观察:若一段序列有$a[l]=a[r]$且$min(a[l+1],...a[r-1])>a[l]$,则$a[l+1],...a[r-1]$在同一颗子树中
    • Gym102483C(Circuit Board Design)题解
    • Gym102433G(Glow, Little Pixel, Glow)题解
    • Codeforces 578D
  • 训练补题

Gym102501J题解

# Gym102501J

题意:给定一个二叉树的中序遍历,且子节点的值一定大于或等于父节点的值,求有多少种二叉树满足该中序遍历。

# 子问题:n个节点的二叉树有多少种形态

  1. 若有1个节点,显然f(1)=1f(1)=1f(1)=1
  2. 若有2个节点,考虑固定一个节点,有f(2)=f(0)∗f(1)+f(1)∗f(0)=2f(2)=f(0)*f(1)+f(1)*f(0)=2f(2)=f(0)∗f(1)+f(1)∗f(0)=2,这里我们定义f(0)=1f(0)=1f(0)=1
  3. 若有3个节点,考虑固定一个节点,则易得f(3)=f(2)+f(1)∗f(1)+f(2)f(3) = f(2)+f(1)*f(1)+f(2)f(3)=f(2)+f(1)∗f(1)+f(2)
  4. 若有n各节点,有f(n)=f(n−1)+f(n−2)f(1)+...+f(1)f(n−2)+f(n−1)f(n)=f(n-1)+f(n-2)f(1)+...+f(1)f(n-2)+f(n-1)f(n)=f(n−1)+f(n−2)f(1)+...+f(1)f(n−2)+f(n−1)

很明显是卡特兰数,祭出公式:f(n)=(2n)!n!(n+1)!f(n)=\frac{(2n)!}{n!(n+1)!}f(n)=n!(n+1)!(2n)!​

# 观察:若一段序列有a[l]=a[r]a[l]=a[r]a[l]=a[r]且min(a[l+1],...a[r−1])>a[l]min(a[l+1],...a[r-1])>a[l]min(a[l+1],...a[r−1])>a[l],则a[l+1],...a[r−1]a[l+1],...a[r-1]a[l+1],...a[r−1]在同一颗子树中

反证法,如果不在同一颗子树,意味着存在a[i]≤a[l](i∉{l,r})a[i]\le a[l]\ (i \notin \{l, r\})a[i]≤a[l](i∈/{l,r}),与前提相违背

处理中序遍历用堆栈!

#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int maxn = 1e6 + 1e5;
const ll mod = 1e9 + 7;

int n, w[maxn];
ll fac[maxn * 2], inv[maxn + 100];

ll qpow(ll base, ll t){
    ll ret = 1;
    while(t){
        if(t & 1) ret = ret * base % mod;
        t >>= 1;
        base = base * base % mod;
    }
    return ret;
}

void init(){
    fac[1] = 1;
    for(int i=2, k=maxn*2; i<k; i++) fac[i] = fac[i-1] * i % mod;
    inv[maxn] = qpow(fac[maxn], mod-2);
    for(int i=maxn-1; i>=0; i--) inv[i] = (inv[i+1]*(i+1)) % mod;
}

int stk[maxn], top = 0;
void solve(){
    cin >> n;
    for(int i=1; i<=n; i++) cin >> w[i];
    w[n+1] = -1;
    ll ans = 1;
    for(int i=1; i<=n+1; i++){
        while(top && stk[top-1] > w[i]){
            int cnt = 0;
            while(cnt < top && stk[top-1] == stk[top-1-cnt]) cnt++;
            top -= cnt;
            ans = ans * fac[2*cnt] % mod * inv[cnt] % mod * inv[cnt+1] % mod;
        }
        stk[top++] = w[i];
    }
    cout << ans << endl;
}

signed main(){
    init();
    solve();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
上次更新: 2021/02/24, 03:37:30
POJ-3468
Gym102483C(Circuit Board Design)题解

← POJ-3468 Gym102483C(Circuit Board Design)题解→

最近更新
01
深入理解Java虚拟机
03-04
02
DNS工作原理
02-27
03
改用VuePress啦
02-23
更多文章>
Theme by Vdoing | Copyright © 2019-2021
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式