Codeforces-1025D:Recovering BST(区间DP)

D. Recovering BST
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Dima the hamster enjoys nibbling different things: cages, sticks, bad problemsetters and even trees!

Recently he found a binary search tree and instinctively nibbled all of its edges, hence messing up the vertices. Dima knows that if Andrew, who has been thoroughly assembling the tree for a long time, comes home and sees his creation demolished, he’ll get extremely upset.

To not let that happen, Dima has to recover the binary search tree. Luckily, he noticed that any two vertices connected by a direct edge had their greatest common divisor value exceed 1.

Help Dima construct such a binary search tree or determine that it’s impossible. The definition and properties of a binary search tree can be found here.

Input
The first line contains the number of vertices n(2n700)n(2≤n≤700).

The second line features n distinct integers ai(2ai109)ai(2≤ai≤109) — the values of vertices in ascending order.

Output
If it is possible to reassemble the binary search tree, such that the greatest common divisor of any two vertices connected by the edge is greater than 1, print “Yes” (quotes for clarity).

Otherwise, print “No” (quotes for clarity).

Examples
input
6
3 6 9 18 36 108
output
Yes
input
2
7 17
output
No
input
9
4 8 10 12 15 18 33 44 81
output
Yes

思路:因为a数组是已经排好序的。所以我们可以用d[L][R]d[L][R]表示区间[L,R][L,R]内的数是否能构成满足题意的二叉树。

所以对于每个区间[L,R][L,R]枚举其根节点ii,于是这个i把这个区间分成了2个子区间[L,i1][L,i−1][i+1,R][i+1,R]即分别为ii的左儿子和右儿子。

但是这样存在一个问题,如何满足题目要求的任意连边的2点的gcd大于1呢?

如果把数组多开一维d[L][R][root]表示区间[L,R][L,R]在以rootroot为根时,是否能满足条件,会超内存。

仔细观察课发现对于一个区间[L,R][L,R],它的根节点只可能是a[L1]a[L−1]a[R+1]a[R+1]
于是可以用d[L][R][0/1]d[L][R][0/1]表示区间[L,R][L,R]在以a[L1]/a[R+1]a[L−1]/a[R+1]为根时,是否满足条件。

#include<bits/stdc++.h>
using namespace std;
const int MOD=998244353;
const int MAX=1e6+10;
const double PI=acos(-1.0);
typedef long long ll;
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int d[710][710][2];
int a[710];
int dfs(int L,int R,int x)
{
    if(L>R)return 1;
    if(d[L][R][x]!=-1)return d[L][R][x];
    int y=(x==0?a[L-1]:a[R+1]);
    for(int i=L;i<=R;i++)
    {
        if(gcd(y,a[i])==1)continue;
        if(dfs(L,i-1,1)&&dfs(i+1,R,0))return d[L][R][x]=1;
    }
    return d[L][R][x]=0;
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    memset(d,-1,sizeof d);
    for(int i=1;i<=n;i++)
    {
        if(dfs(1,i-1,1)&&dfs(i+1,n,0))
        {
            puts("Yes");
            return 0;
        }
    }
    puts("No");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值