1. 程式人生 > >Codeforces Round #505 D Recovering BST(cf 1025D)

Codeforces Round #505 D Recovering BST(cf 1025D)

題意:給出n個升序排列的數,求是否能用這n個數組成一顆二叉排序樹。

思路:
考場上——看標題,BST!看了題面後,我zz的想,這不就是裸的圖論題麼…然後就一頓敲,交上去一遍AC,心裡美滋滋。結果正式測評就在51個點WA了。
其實正解是dp。
令L[i][j]表示以i為根,i的左子樹可到j 這樣的bst是否存在。
同理R[i][j]表示以i為根,i的右子樹可到j 這樣的bst是否存在。
然後列舉一箇中間變數進行轉移。
比如說L的轉移:其中g[i][p]為true是為了判斷p可與i相連,而L[p][k]即是指p的左兒子可擴充套件到k。由於是BST,所以i+1一定是i的祖先或在i的右子樹中。R[i+1][p]為true指i+1可擴充套件到p,也就是指i+1是i的祖先。 所以可以看出,p是i的父親,i+1為i的祖先時,i只有左子樹,所以可以利用p的左子樹進行轉移。
最後,如果存在一個i使得L[i][n]==R[1][i]==1,則說明存在一顆以i為根的bst,否則不存在。

程式碼:

#include<bits/stdc++.h>
using namespace std;

#define maxn 700
#define rep(i,x,y) for(int i=x;i<=y;i++)

int n;
int a[maxn+5];
int g[maxn+5][maxn+5];
bool L[maxn+5][maxn+5],R[maxn+5][maxn+5];

int GCD(int x,int y) {
    if(y==0) return x;
    return GCD(y,x%y);
}

int main() {
    scanf
("%d",&n); rep(i,1,n) { scanf("%d",&a[i]); } rep(i,1,n) { rep(j,1,n) { g[i][j]=GCD(a[i],a[j]); if(g[i][j]==1) g[i][j]=0; else g[i][j]=1; } } rep(i,1,n) L[i][i]=R[i][i]=1; rep(j,1,n-1) rep(i,1,n-j) { int
k=i+j; rep(p,i+1,k) L[i][k]|=(g[i][p]&L[p][k]&R[i+1][p]); rep(p,i,k-1) R[i][k]|=(g[p][k]&L[p][k-1]&R[i][p]); } rep(i,1,n) { if(L[i][n]&&R[1][i]) { printf("Yes"); return 0; } } printf("No"); return 0; }