题解[CF1025D Recovering BST]
题意简述
给定一棵\(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;
}