「CF1025D」Recovering BST
考虑区间 \(\text{DP}\),设 \(L_{i, j}\),表示区间 \([i + 1, j]\) 表示的子树能否作为 \(i\) 的右子树。(在中序遍历上)。
\(R_{i, j}\) 类似。
那么我们每次考虑从下往上 \(\text{DP}\):考虑一颗合法的子树 \([i, j]\),我们首先要给他定根 \(k\),不难发现如果有 \(L_{i, k} = 1\) 且 \(R_{k, j} = 1\),\(k\) 就是合法的。
考虑把这颗子树往上接,那么有 \(R_{i - 1, j} = f_{i - 1, k}, L_{i, j + 1} = f_{k, j + 1}\),\(f_{i, j}\) 表示 \(i\) 和 \(j\) 能否直接相连。
那么有解的情况就是能找到一个 \(k\) 使得 \(L_{1, k} = 1\) 且 \(R_{k, n} = 1\)。
参考代码:
#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline void swap(T& a, T& b) { T t = a; a = b; b = t; }
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
}
const int _ = 702;
int n, a[_], f[_][_], L[_][_], R[_][_];
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n);
for (rg int i = 1; i <= n; ++i) read(a[i]), L[i][i] = R[i][i] = 1;
for (rg int i = 1; i <= n; ++i)
for (rg int j = i + 1; j <= n; ++j)
if (gcd(a[i], a[j]) != 1) f[i][j] = f[j][i] = 1;
for (rg int l = 1; l <= n; ++l)
for (rg int i = 1, j = i + l - 1; j <= n; ++i, ++j)
for (rg int k = i; k <= j; ++k)
if (L[i][k] && R[k][j]) {
if (i == 1 && j == n) { puts("Yes"); return 0; }
if (f[i - 1][k]) R[i - 1][j] = 1;
if (f[k][j + 1]) L[i][j + 1] = 1;
}
puts("No");
return 0;
}

浙公网安备 33010602011771号