Codeforces Round #505 D Recovering BST(cf 1025D)
阿新 • • 發佈:2018-12-23
題意:給出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;
}