zoukankan      html  css  js  c++  java
  • CF1025D Recovering BST 题解

    Codeforces
    Luogu

    Description.

    给定 (n) 个数,问能否构成一个二叉排序树,使得每条边两端 (gcd>1)

    (nle 700)

    Solution.

    性质什么的很显然,一个子树肯定是一个区间,根要么是左边要么是右边。
    首先有一个 (O(n^5)) 的 dp,定义 dp[l][r][k] 表示 ([l,r]) 作为子树,(k) 作为根能否可行。
    每次枚举最后的根,枚举左端点的根,枚举右端点的根,复杂度达到了 (O(n^5)) 过不去(吧)

    发现左子树和右子树其实本质相同,而且我们对于一个区间,它的根是确定的。
    我们可以考虑分别设两个 dp 表示它作为左子树、右子树是否可行。
    考虑这个能否转移,首先左边右边两段区间拼起来可以得到当前这个区间是否可行。
    然后枚举分界点时,分界点肯定是根,然后就免去了暴力枚根的时间。
    总复杂度变成了 (O(n^3)) 加上区间 dp 小常数。

    Coding.

    点击查看代码
    //Coded by Kamiyama_Shiki on 2021.11.05 {{{
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
    const int N=705;int n,a[N],w[N][N],dp[N][N][2];
    inline int gcd(int x,int y) {return y?gcd(y,x%y):x;}
    int main()
    {
    	read(n);for(int i=1;i<=n;i++) read(a[i]);
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) w[i][j]=gcd(a[i],a[j]);
    	for(int i=1;i<=n;i++) dp[i][i-1][0]=dp[i+1][i][1]=1;
    	for(int ln=0;ln<n;ln++) for(int l=1,r=l+ln;r<=n;l++,r++)
    		for(int k=l;k<=r;k++) if(dp[l][k-1][0]&&dp[k+1][r][1])
    		{
    			if(l==1&&r==n) return puts("Yes"),0;
    			if(l!=1&&w[k][l-1]!=1) dp[l][r][1]=1;
    			if(r!=n&&w[k][r+1]!=1) dp[l][r][0]=1;
    		}
    	return puts("No"),0;
    }
    
  • 相关阅读:
    AIO异步非阻塞学习
    Netty TCP粘包/拆包问题《二》
    Netty TCP粘包/拆包问题《一》
    修改host文件屏蔽视频广告和网站
    HTML DOM参考手册
    PPT图片快速编辑技巧
    ExtJS ComboBox的用法+代码
    4_python之路之模拟工资管理系统
    3_python之路之商城购物车
    2_python之路之多级菜单
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15520357.html
Copyright © 2011-2022 走看看