CF 505D. Recovering BST 降维,DP

题意:长度为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;
}

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值