题目连接
青木君很喜欢数列和树。
一天,高桥君给了他一个长度为 \(N\) 的数列 \(a1, a2, …, aN\),这让青木有了构造一棵树的冲动。
他想要构造一棵树,其中 \(i\) 号点与其它点的树上距离的最大值恰好等于 \(ai\)(假设树边长度均为\(1\))。
请问是否存在这样一棵树符合要求。
sol
这种题目可以从极端情况入手,而这里的极端就是树的直径。
-
因为任何树都存在至少一条直径,所以一定存在一对相等且最大的 \(a[u]\) 和 \(a[v]\) ,其中 \(u\) 和 \(v\) 是直径的两端,如果不存在,输出 \(Impossible\) ;
-
找到直径后,直径上的所有点的 \(a[i]\) 都可以推出,如果给出的 \(a\) 序列中找不到对应的值,输出 \(Impossible\);
-
接下来,其余点都相当于挂在直径这条链的两侧(不允许挂在 \(u\) 和 \(v\) 上,否则直径会更长)。显然,如果这些点的 \(a[i]\) 值没有大于直径的一半(向上取整),我们把这个长度设为 \(mid\) ,那么他显然不可以出现在链上,所以输出 \(Impossible\);否则,一定可以构造出符合条件的悬挂方式:由于剩余点的 \(a[i]∈[mid+1,a[u]]\) ,所以一定可以在直径上找到一个距离 \(u\)或 \(v\) 恰好为 \(a[i]-1\) 的点 \(x\),将 \(i\) 和 \(x\) 连接,使得 \(a[i]\) 符合要求。由于新加的边长度都为 \(1\) ,不会使链变长。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int N,cnt[maxn],a[maxn];
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int main(){
freopen("Half Reflector.in","r",stdin);
freopen("Half Reflector.out","w",stdout);
N=read();
for(int i=1;i<=N;i++) cnt[a[i]=read()]++;
sort(a+1,a+1+N);
if(a[N-1]!=a[N]) return printf("Impossible\n"),0;
cnt[a[N]]-=2;
for(int i=1;i<a[N];i++){
int d=max(i,a[N]-i);
if(cnt[d]<1) return printf("Impossible\n"),0;
cnt[d]--;
}
for(int i=1;i<=(a[N]+1>>1);i++)if(cnt[i]) return printf("Impossible\n"),0;
printf("Possible\n");
return 0;
}