【题解】CF1025D:Recovering BST

原题传送门
首先会想到一个朴素的暴力
d p i , j , k dp_{i,j,k} 表示区间 [ i , j ] [i,j] 根为 k k 是否可行,枚举两边子树的根
复杂度 O ( n 4 ) O(n^4)

这是逆推dp,一般逆推不行,可以想一想顺推
对于一个区间 [ i , j ] [i,j] ,它的父亲只能为 i 1 j + 1 i-1或j+1 ,可以枚举区间 [ i , j ] [i,j] 以及区间的根 k k ,往 [ i 1 , j ] , [ i , j + 1 ] [i-1,j],[i,j+1] 两个状态推
这样复杂度是 O ( n 3 ) O(n^3) 跑不满,可以接受

Code:

#include <bits/stdc++.h>
#define maxn 710
using namespace std;
int a[maxn], dp[maxn][maxn][2], g[maxn][maxn], n;

inline int read(){
	int s = 0, w = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
	for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
	return s * w;
}

int gcd(int m, int n){ return !n ? m : gcd(n, m % n); }

int main(){
	n = read();
	for (int i = 1; i <= n; ++i) a[i] = read(), dp[i][i][0] = dp[i][i][1] = 1;
	for (int i = 1; i <= n; ++i)
		for (int j = i + 1; j <= n; ++j) g[i][j] = gcd(a[i], a[j]);
	for (int l = 1; l <= n; ++l)
		for (int i = 1, j = i + l - 1; j <= n; ++i, ++j)
			for (int k = i; k <= j; ++k)
				if (dp[i][k][1] && dp[k][j][0]){
					if (i == 1 && j == n) return puts("Yes"), 0;
					if (g[i - 1][k] > 1) dp[i - 1][j][0] = 1;
					if (g[k][j + 1] > 1) dp[i][j + 1][1] = 1;
				}
	puts("No");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/ModestCoder_/article/details/108350106
BST