2018GDUT第一场C 遗失的二叉树(区间dp)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kzn2683331518/article/details/83212485

问题描述:

给定一个序列,判断其是否可能为一个二叉树的中序遍历序列,该二叉树树边连接的两个点的值不能互质。

输入描述:

第一行一个数字T,表示测试组数

对于每一组测试样例

第一行一个数字n,表示序列长度

第二行有n个数字ai,表示这个序列

T≤5,n≤500,2≤ai≤10^9

输出格式:

输出T行,"Yes"或"No"

输入样例:

2
6
5 4 7 9 5 4
4
2 6 3 4

输出样例:

No
Yes

题目分析:

n才500,预处理出 ok[i][j] 表示a[i]与a[j]之间可以连树边。接下来考虑区间 dp,L[l][r]表示区间[l,r] 是否可以作为 r 的左儿子,R[l][r]表示区间[l,r]是否可以作为 l 的右儿子。

那么 L[l][r]=true 的前提是存在一个k(l≤k≤r-1)满足: L[l][k]&&R[k][r-1]&&ok[k][r]

同理 R[l][r]=true 的前提是存在一个k(l+1≤k≤r)满足:L[l+1][k]&&R[k][r]&&ok[l][k]

分析之后发现区间dp复杂度为n^3,n为500,样例好像比较水,1s时间能过。

AC代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define lowbit(a) ((a)&(-(a)))
#define ll long long
using namespace std;
int n,m,a[505];
bool L[505][505],R[505][505],ok[505][505];
inline void init(){
    for(int i=1;i<=n;i++){
        L[i][i]=R[i][i]=ok[i][i]=1;
        for(int j=1;j<i;j++){
            L[i][j]=L[j][i]=R[i][j]=R[j][i]=ok[i][j]=ok[j][i]=0;
        }
    }
}
int main(){
    int t;  scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        
        for(int i=1;i<=n;i++){          //预处理
            for(int j=1;j<i;j++){
                if(__gcd(a[i],a[j])!=1)ok[i][j]=ok[j][i]=true;
                else ok[i][j]=ok[j][i]=false;
            }
        }
        
        for(int len=1;len<=n;len++){
            
            for(int i=len+1;i<=n;i++)  //L[i-len][i]
                for(int j=i-len;j<=i-1;j++)
                    if(L[i-len][j]&&R[j][i-1]&&ok[i][j]){
                        L[i-len][i]=true;
                        break;
                    }
            
            for(int i=1;i<=n-len;i++)  //R[i][i+len]
                for(int j=i+1;j<=i+len;j++)
                    if(L[i+1][j]&&R[j][i+len]&&ok[i][j]){
                        R[i][i+len]=true;
                        break;
                    }
            
        }
        
        bool flag=false;
        for(int i=1;i<=n;i++)
            if(L[1][i]&&R[i][n]){
                flag=true;
                break;
            }
        if(flag)
            puts("Yes");
        else
            puts("No");
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/kzn2683331518/article/details/83212485