原题传送门
首先会想到一个朴素的暴力
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k表示区间
[
i
,
j
]
[i,j]
[i,j]根为
k
k
k是否可行,枚举两边子树的根
复杂度
O
(
n
4
)
O(n^4)
O(n4)
这是逆推dp,一般逆推不行,可以想一想顺推
对于一个区间
[
i
,
j
]
[i,j]
[i,j],它的父亲只能为
i
−
1
或
j
+
1
i-1或j+1
i−1或j+1,可以枚举区间
[
i
,
j
]
[i,j]
[i,j]以及区间的根
k
k
k,往
[
i
−
1
,
j
]
,
[
i
,
j
+
1
]
[i-1,j],[i,j+1]
[i−1,j],[i,j+1]两个状态推
这样复杂度是
O
(
n
3
)
O(n^3)
O(n3)跑不满,可以接受
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;
}