「Link」
一道 trivial 的 DP
定义 fi,j 为序列为 si…j 的树的个数
si=sj 显然 fi,j=0
考虑如何处理 fi,j
- i=j 就是只有一个节点
- 有一个或多个子节点,考虑第一个子树是在哪里断
具体来说,考虑所有 sk=si=sj(i<k≤r)
钦定 si+1…k−1 为一棵子树
其余的丢到以后考虑
fi,j=i<k≤j,sk=si∑fi+1,k−1⋅fk,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) { 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 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]; return 0; }
|