题意简述
给定一棵(BST)的点数和点权,且满足相连的点的最小公约数都不为(1) ,问是否能还原 这棵(BST)的形态。
Sol
题目给出的点权序列是有序的,而且又是一棵(BST) ,所以对于区间([l,r])而言,这整个区间的点的父亲一定是(l-1)或(r+1) 。
设(f[l][r][rt])为区间([l,r])能否以(rt)作为根节点,(rt in [l,r]) 。
(O(n^4))的状态转移就出来了~
时间炸了空间炸了
考虑更优的做法。设(f[i][j][0/1])为区间([i,j])能否以(i-1,j+1)作为根。
枚举区间,根。
如果区间([i,k])能(i-1)为根且区间([k,j])能以([j+1])为根,说明这两棵树有合并的可能,考虑最终([i-1,j+1])这棵大树是以谁为根((i-1)或(j+1))。
再如果,(i-1)可以和(k)合并,那区间([i-1,k])就能以(j+1)为根。
另一边同理。
Code
#include<bits/stdc++.h>
#define N (710)
using namespace std;
int n,a[N],f[N][N][2];
bool g[N][N];
inline int read(){
int w=0;
char ch=getchar();
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9'){
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w;
}
inline int mgcd(int a,int b){
if(!b) return a;
return mgcd(b,a%b);
}
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read(),f[i][i][0]=f[i][i][1]=1;
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(mgcd(a[i],a[j])!=1) g[i][j]=g[j][i]=1;//预处理能否合并
for(int len=1;len<=n;len++){
for(int i=1,j;i+len-1<=n;i++){
j=i+len-1;
for(int k=i;k<=j;k++){
if(f[i][k][0]&&f[k][j][1]){
if(i==1&&j==n){
puts("Yes");
return 0;
}
if(g[i-1][k]) f[i-1][j][1]=1;
if(g[k][j+1]) f[i][j+1][0]=1;
}
}
}
}
puts("No");
return 0;
}