[关闭]
@ysner 2018-08-21T14:28:14.000000Z 字数 1307 阅读 2107

[CF1025D]Recovering BST

DP 二叉搜索树


题面

给出一些数,若要求两数才能连边,询问他们是否能构成一棵二叉搜索树

解析

如果没注意到二叉搜索树这一条件,这题绝对做不出来。。。

二叉搜索树的定义是,对同一节点,左儿子权值比它小,右儿子权值比它大。
于是有一个很重要的性质,中序遍历上点权从小到大

可以得出推论:

然而注意到,如果暴力设表示以为根,作为其左/右儿子是否合法是会,而且有许多无效状态。

于是需应用上面推论,设两个判合法性的数组:

转移:
为区间的根,
如果,则该状态合法,可以转移;
没地方转移了就
如果可以与相连,说明以为根,为右儿子的状态合法。
如果可以与相连,说明以为根,为左儿子的状态合法。

Ps:联想到了另一道题

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. il ll gi()
  14. {
  15. re ll x=0,p=1;
  16. re char ch=getchar();
  17. while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
  18. if(ch=='-') p=-1,ch=getchar();
  19. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  20. return p*x;
  21. }
  22. const int N=710;
  23. int n,a[N],f[N][N],L[N][N],R[N][N];
  24. int main()
  25. {
  26. ios::sync_with_stdio(false);
  27. cin>>n;
  28. for(int i=1;i<=n;i++) cin>>a[i],L[i][i]=R[i][i]=1;
  29. fp(i,1,n) fp(j,i,n) if(__gcd(a[i],a[j])>1) f[i][j]=f[j][i]=1;
  30. fq(l,n,1)
  31. fp(r,l,n)
  32. fp(k,l,r)
  33. if(L[l][k]&&R[k][r])
  34. {
  35. if(l==1&&r==n) {puts("Yes");return 0;}
  36. if(f[l-1][k]) R[l-1][r]=1;
  37. if(f[k][r+1]) L[l][r+1]=1;
  38. }
  39. puts("No");
  40. return 0;
  41. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注