CF1025D Recovering BST

生来就可爱ヽ(ⅴ<●) 提交于 2020-02-02 05:55:29

一、题目

点此看题

二、解法

考虑暴力做法,设f[l][r][u][0/1]f[l][r][u][0/1]表示[l,r][l,r]作为uu的左儿子//右儿子是否合法,但是这种做法在n<=700的数据中会MLE

考虑压缩无用的状态,由于我们需要构造的是一颗二叉搜索树,所以一段区间[l,r][l,r]如果作为左儿子,那么根一定是r+1r+1,并且一段区间是否合法是可以通过枚举根节点来判断的,于是我们可以这么定义状态:

  • L[l,r]L[l,r]表示[l,r1][l,r-1]作为rr的左端点是否合法
  • R[l,r]R[l,r]表示[l+1,r][l+1,r]作为ll的右端点是否合法

然后就可以愉快的转移了,我们左端点从大到小,右端点从小到大,来枚举一个区间,我们首先判断这个区间是否合法,枚举根(从L[l,k],R[k,r]L[l,k],R[k,r]来判断),然后看l1l-1r+1r+1能不能接到这个根上,以此来更新状态,初始值L[i][i]=R[i][i]=1L[i][i]=R[i][i]=1,我们在转移过程中如果l=1,r=nl=1,r=n被判定为合法,那么就输出Yes,否则输出No

时间复杂度O(n3)O(n^3),贴个代码qwqqwq

#include <cstdio>
const int M = 705;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,a[M],f[M][M],L[M][M],R[M][M];
int gcd(int a,int b)
{
    return !b?a:gcd(b,a%b);
}
int main()
{
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read(),L[i][i]=R[i][i]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(gcd(a[i],a[j])!=1)
                f[i][j]=1;
    for(int i=n;i>=1;i--)
        for(int j=i;j<=n;j++)
            for(int k=i;k<=j;k++)
                if(L[i][k]&&R[k][j])
                {
                    if(i==1 && j==n) {puts("Yes");return 0;}
                    if(f[i-1][k]) R[i-1][j]=1;
                    if(f[k][j+1]) L[i][j+1]=1;
                }
    puts("No");
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!