zoukankan      html  css  js  c++  java
  • D. Recovering BST 区间DP

    D. Recovering BST 区间DP

    题目大意:

    给你一个不递减大小为n的一个序列,如果两个数的最大公约数大于1,那么这两个数可以建一条边,问最后是否可以构成一颗二叉搜索树。

    题解:

    这个题目写了很久,一直也没有想明白怎么写,不过可以发现的是这个是一个区间DP,然而因为这个数据范围让我又以为不是区间DP。

    最后看了题解,非常巧妙的一个想法。

    正常的来说,应该是定义:(dp[i][j][k]) 表示从 (i)(j)(k) 为根节点,但是这样的复杂度就太高了 (O(n^5)) ,考虑进行优化,因为这个是一个二叉搜索树,所以如果我知道了左子树是 ([i,j]) 那么这个树的根节点应该是 (i+1) ,如果 ([i,j]) 是右子树的话,那么这棵树的根节点应该是 (i-1) ,这个我觉得还是蛮难发现的,可能是我做的题目太少了。

    可以思考一下这个转移方程:

    • 两棵子树拼接
    • 一棵树和一个节点拼接
    #include <bits/stdc++.h>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    const int maxn = 1e3+10;
    typedef long long ll;
    int a[maxn];
    int dp[maxn][maxn][2],e[maxn][maxn];
    int gcd(int a,int b){
        return b==0?a:gcd(b,a%b);
    }
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                e[i][j] = (gcd(a[i],a[j])!=1);
        for(int i=1;i<=n;i++){
            if(i>1&&e[i-1][i]) dp[i][i][1] = 1;//right
            if(i<n&&e[i+1][i]) dp[i][i][0] = 1;//left
        }
        for(int len=1;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j = i + len - 1;
                if(dp[i][j][0]){
                    for(int k=j+2;k<=n;k++){
                        if(dp[j+2][k][1]){
                            if(e[j+1][k+1]) dp[i][k][0] = 1;
                            if(e[j+1][i-1]) dp[i][k][1] = 1;
                        }
                    }
                    if(e[j+1][j+2]) dp[i][j+1][0] = 1;
                    if(e[j+1][i-1]) dp[i][j+1][1] = 1;
                }
                if(dp[i][j][1]){
                    for(int k=1;k<=i-2;k++){
                        if(dp[k][i-2][0]){
                            if(e[i-1][j+1]) dp[k][j][0] = 1;
                            if(e[i-1][k-1]) dp[k][j][1] = 1;
                        }
                    }
                    if(e[i-1][j+1]) dp[i-1][j][0] = 1;
                    if(e[i-1][i-2]) dp[i-1][j][1] = 1;
                }
            }
        }
        dp[1][0][0] = 1;
        bool flag = dp[1][n-1][0];
        for(int i=2;i<=n;i++){
            if(dp[1][i-2][0]&&dp[i][n][1]) flag = true;
        }
        if(flag) printf("Yes
    ");
        else printf("No
    ");
        return 0;
    }
    
  • 相关阅读:
    android原子
    android进程优先级
    Android 的cyclicBarrier
    android中运用CountDownLatch
    java网络编程长连接的问题
    https
    http 上传文件
    netty4 断线重连
    Linux下高并发socket最大连接数所受的各种限制
    Android Studio NDK及so文件开发
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/14353834.html
Copyright © 2011-2022 走看看