题解[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;
}

完结撒花❀

posted @ 2021-02-20 17:26  xxbbkk  阅读(98)  评论(0编辑  收藏  举报