题意:长度为n的序列a.问是否能通过序列a构造出一棵n个节点的BST.并且若有边(u,v) 则gcd(u,v)>1.
n<=700, 1<=a[i]<=1e9.
设f[l][r][i] 序列[L,L+1..R]并且以i为根时 是否能构造出合法的BST.
F[L][R][u] = f[L][u-1][x] && f[u+1][R][y] . gcd(x,u) >1 && gcd(y,u)>1 .
O(N^4)TLE.....
对于区间[L,R] 枚举一个节点u作为根节点 则问题分为两半, [L,u-1],[u+1,R]
比如[L,u-1]被分在左边 那么就能知道这个子区间父节点为u .
所以设dp[L][R][0/1] 则在[L,R]枚举根节点时,根据side就可以知道它的父节点是a[R+1]还是a[L-1] 然后做gcd判断.O(N^3)
#include <bits/stdc++.h>
using namespace std;
const int N=7e2+5;
int n,a[N];
short f[N][N][2];
bool can[N][N];
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
bool solve(int l,int r,int side){
if(f[l][r][side]!=-1) return f[l][r][side];
int rt=r+1;
if(side==1) rt=l-1;
if(l>r) return true;
for(int i=l;i<=r;i++){
if(can[i][rt]==true&&solve(l,i-1,0)&&solve(i+1,r,1))
return f[l][r][side]=true;
}
return f[l][r][side]=false;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],can[i][0]=true;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(gcd(a[i],a[j])>1)can[i][j]=true;
memset(f,-1,sizeof(f));
bool flag=solve(1,n,1);
if(flag)cout<<"Yes"<<'\n';
else cout<<"No"<<'\n';
return 0;
}