题意介绍
在瑞神大战宇宙射线中我们了解到了宇宙狗的厉害之处,虽然宇宙狗凶神恶煞,但是宇宙狗有一个很可爱的女朋友。
最近,他的女朋友得到了一些数,同时,她还很喜欢树,所以她打算把得到的数拼成一颗树。
这一天,她快拼完了,同时她和好友相约假期出去玩。贪吃的宇宙狗不小心把树的树枝都吃掉了。所以恐惧包围了宇宙狗,他现在要恢复整棵树,但是它只知道这棵树是一颗二叉搜索树,同时任意树边相连的两个节点的gcd(greatest common divisor)都超过1。
但是宇宙狗只会发射宇宙射线,他来请求你的帮助,问你能否帮他解决这个问题。
题意分析
动态规划,dp[i][rt-1][0]和dp[rt+1][r][1],其中dp[i][j][0]表示[i,j]是j+1的左子树,dp[i][j][1]表示[i,j]是i-1的右子树。
通过代码
#include<bits/stdc++.h>
using namespace std;
#define maxn 701
int t, n,a[maxn],g[maxn][maxn],dp[maxn][maxn][2];
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a%b);
}
int main() {
cin >> t;
while (t--) {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i != j) {
g[i][j] = (gcd(a[i], a[j])!=1);
}
}
}
for (int i = 1; i <= n; i++) {
dp[i][i][0] = 1;
dp[i][i][1] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int k = i + j - 1;
if (k <= n) {
for (int l = j + 1; l <= k; l++)
dp[j][k][0] |= (g[j][l] && dp[j + 1][l][1] && dp[l][k][0]);
for (int l = j; l < k; l++)
dp[j][k][1] |= (g[l][k] && dp[j][l][1] && dp[l][k - 1][0]);
}
}
}
bool flag = false;
for (int i = 1; i <= n; i++) {
if (dp[1][i][1] && dp[i][n][0]) {
cout << "Yes" << endl;
flag = true;
break;
}
}
if(!flag)cout << "No" << endl;
}
return 0;
}