「CH 5302」金字塔

「Link」

一道 trivial 的 DP

定义 fi,jf_{i, j} 为序列为 sijs_{i\dots j} 的树的个数

sisjs_i\neq s_j 显然 fi,j=0f_{i,j}=0

考虑如何处理 fi,jf_{i,j}

  • i=ji=j 就是只有一个节点
  • 有一个或多个子节点,考虑第一个子树是在哪里断

具体来说,考虑所有 sk=si=sj(i<kr)s_k=s_i=s_j(i<k\le r)

钦定 si+1k1s_{i+1\dots k-1} 为一棵子树

其余的丢到以后考虑

fi,j=i<kj,sk=sifi+1,k1fk,j f_{i,j}=\sum_{i<k\le j,s_k=s_i} f_{i+1, k-1}\cdot f_{k,j}

记忆化搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const int MOD = 1e9;
int f[N][N];

int calc(int l, int r) {
// cerr << l << ' ' << r << endl;
if (f[l][r] != -1) return f[l][r];
if (l == r) return f[l][r] = 1;
int ret = 0;
rep(k, l + 1, r) {
if (s[k] == s[l]) {
(ret += (ll)calc(l + 1, k - 1) * calc(k, r) % MOD) %= MOD;
}
}
return f[l][r] = ret;
}

递推

1
2
3
4
5
6
7
8
rep(i, 1, n) f[i][i] = 1;
for (int len = 2; len <= n; len += 2) // 事实证明长度肯定为奇数
rep(i, 1, n - len){
int j = i + len;
rep(k, i + 1, j)
if (s[i] == s[k])
(f[i][j] += (ll)f[i + 1][k - 1] * f[k][j] % MOD) %= MOD;
}
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, l, r) for (int i = (l); i >= (r); --i)
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::make_pair;
using std::pair;
typedef pair<int, int> pii;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;

const int N = 310;
char s[N];

const int MOD = 1e9;
int f[N][N];

// int calc(int l, int r) {
// // cerr << l << ' ' << r << endl;
// if (f[l][r] != -1) return f[l][r];
// if (l == r) return f[l][r] = 1;
// int ret = 0;
// rep(k, l + 1, r) {
// if (s[k] == s[l]) {
// (ret += (ll)calc(l + 1, k - 1) * calc(k, r) % MOD) %= MOD;
// }
// }
// return f[l][r] = ret;
// }

int main() {
#ifdef LOCAL
freopen("input", "r", stdin);
#endif
std::ios::sync_with_stdio(false);
cout.tie(0);
cin >> s + 1;
int n = strlen(s + 1);
rep(i, 1, n) f[i][i] = 1;
for (int len = 2; len <= n; len += 2) {
rep(i, 1, n - len) {
int j = i + len;
rep(k, i + 1, j) {
if (s[i] == s[k]) {
(f[i][j] += (ll)f[i + 1][k - 1] * f[k][j] % MOD) %= MOD;
}
}
}
}
cout << f[1][n];
// std::memset(f, -1, sizeof(f));
// cout << calc(1, n);
return 0;
}
作者

Gesrua

发布于

2019-10-04

更新于

2020-11-21

许可协议