codeforces 1025 D. Recovering BST(区间dp)

17 篇文章 0 订阅

http://codeforces.com/problemset/problem/1025/D

题目大意:给出n个数字,问能不能使用这些数字构成binary search tree,相邻节点gcd>1;

思路:这道题要用到区间dp知识的知识

博客:
https://blog.csdn.net/my_sunshine26/article/details/77141398

区间dp中,把断点k当做树的根节点,若以第 k 个结点为根节点
用 l[i][k] 表示是否能够向左延伸到 i 点
r[k][j] 表示是否能够向右延伸到 j 点。
k 作为[l, r]的根,就可以判断gcd能否用L[l][r] 和 R[l][r] 更新 R[l-1][r] 和 L[l][r+1]。
因为这里l-1或者r-1会是这段区间的父亲,对于每个区间[L,R][L,R]枚举其根节点k,于是这个k把这个区间分成了2个子区间[L,i−1]和[i+1,R]即分别为ii的左儿子和右儿子。当父亲在左边,表示父亲可右扩展到j,左边同理,
can[i][j]表示这个区间可以作为BST ,如果能的话 can[1][n]=1

#include<bits/stdc++.h>
#define fi first
#define se second
#define log2(a) log(n)/log(2)
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
#define tim printf("Time cost : %lf s\n",(double)clock()/CLOCKS_PER_SEC);
using namespace std;

typedef long long ll;
typedef long long LL;
typedef pair<int, int> P;
typedef pair<P, ll> LP;
const ll inf = 1e18;
const int N = 1e6 + 10;
const ll mod = 1e9 + 7;
const int base = 131;
const double pi = acos ( -1 );
const double eps = 1e-8;
inline ll ksm(ll a,ll b){ll ans=1;while(b){if(b&1)ans=ans*a%mod;a=a*a%mod,b>>=1;}return ans;}
#define a(i,j) a[(i-1)*m+(j)]
#define b(i,j) b[(i-1)*m+(j)]

ll  vis[N],num[N];
ll n, m,  k, x, y, z;
ll a[N], b[N],c[N];
ll cx, cy, cnt, ans, sum, flag, t, ff,q;

struct node
{
	ll to,k;
};
//vector<int> v[N],res;

unordered_map<int, int> mp;
set<string> st;
ll dep[N];
ll l[705][705],r[705][705],v[705][705],can[705][705];


int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);

	cin>>n;

	for(int i=1;i<=n;i++) cin>>a[i],l[i][i]=r[i][i]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)
		{
			v[i][j]=v[j][i]=(__gcd(a[i],a[j])!=1);
		}
	}
	for(int len=1;len<=n;len++)
	for(int i=1;i<=n;i++)
	{
		int j=i+len-1;
		if(j>n) break;
		for(int k=i;k<=j;k++)
		{
			if(l[i][k]&&r[k][j])
			{
				can[i][j]=1;
				if(v[i-1][k]) r[i-1][j]=1;//父节点在左
				if(v[k][j+1]) l[i][j+1]=1;//父节点在右
			}
		}
	}
	if(can[1][n]) cout<<"Yes";
	else cout<<"No";








}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值