[AGC005C Tree Restoring] [貪心構造]
阿新 • • 發佈:2018-12-10
[題目大意]
青木君很喜歡數列和樹。
一天,高橋君給了他一個長度為N的數列a1, a2, …, aN,這讓青木有了構造一棵樹的衝動。
他想要構造一棵樹,其中i號點與其它點的樹上距離的最大值恰好等於ai(假設樹邊長度均為1)。
請問是否存在這樣一棵樹符合要求。
[想法]
這種題目可以從極端情況入手,而這裡的極端就是樹的直徑。
(1)因為任何樹都存在至少一條直徑,所以一定存在一對相等且最大的a[u]和a[v],其中u和v是直徑的兩端,如果不存在,輸出Impossible;
(2)找到直徑後,直徑上的所有點的a[i]都可以推出,如果給出的a序列中找不到對應的值,輸出Impossible;
(3)接下來,其餘點都相當於掛在直徑這條鏈的兩側(不允許掛在u和v上,否則直徑會更長)。
(3-1)顯然,如果這些點的a[i]值沒有大於直徑的一半(向上取整)mid,它們不可能掛在鏈的外側,所以輸出Impossible;
(3-2)否則,一定可以構造出符合條件的懸掛方式:由於剩餘點的a[i]∈[mid+1,a[u]],所以一定可以在直徑上找到一個距離u恰好為a[i]-1的點x,將i和x連線,使得a[i]符合要求。同時,所有點都是直接懸掛的,所以不會產生更長的鏈,可以發現其它點的a[i]仍然符合要求。
注意一個小坑點:a={1,1},這種情況顯然應該輸出Possible,但是程式考慮不周的話可能會出現小BUG,如果莫名WA,可以試試這個樣例。
#include <cstdio> #include <algorithm> #define rep(i,j,k) for (i=j;i<=k;i++) using namespace std; const int N=1e5+5; int n,i,d,a[N],cnt[N]; int main() { scanf("%d",&n); rep(i,1,n) { scanf("%d",&a[i]); cnt[a[i]]++; } sort(a+1,a+1+n); if (a[n-1]!=a[n]) { printf("Impossible\n"); return 0; } cnt[a[n]]-=2; rep(i,1,a[n]-1) { d=max(i,a[n]-i); if (cnt[d]<1) { printf("Impossible\n"); return 0; } cnt[d]--; } rep(i,1,(a[n]+1)/2) if (cnt[i]) { printf("Impossible\n"); return 0; } printf("Possible\n"); return 0; }