某个公司有n个人, 上下级关系构成了一个有根树。其中有个人是叛徒(这个人不知道是谁)。对于一个人, 如果他
下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变
成叛徒。你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。
标签:poi == ext printf 公司 16px 一个人 name 而且
题解:一眼看题就觉得是二分,后来发现二分根本没有必要,而且会TLE
设f[i]表示无法使i的子树中所有人都变成叛徒的最小x,可以列出方程
f[i]=max( f[i],min( f[j],siz[j]/( siz[i]-1 ) ) ) (j是i的儿子)
也就是说,如果j的子树大小所占比例高于x,并且让j全变成叛徒需要的x比当前值大,都会使i也变成叛徒,所以f[i]必须必他们的最小值大才可以
注意答案不是f[1],而是所有满足siz[i]>k的f[i]的最大值
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int maxn=500010; int n,cnt,m; double ans,f[maxn]; int siz[maxn],to[maxn],next[maxn],head[maxn]; void add(int a,int b) { to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; } void dfs(int x) { siz[x]=1; for(int i=head[x];i!=-1;i=next[i]) dfs(to[i]),siz[x]+=siz[to[i]]; if(siz[x]==1) f[x]=1.0; for(int i=head[x];i!=-1;i=next[i]) f[x]=max(f[x],min(f[to[i]],1.0*siz[to[i]]/(siz[x]-1.0))); } int main() { scanf("%d%d",&n,&m); int i,a; memset(head,-1,sizeof(head)); for(i=2;i<=n;i++) scanf("%d",&a),add(a,i); dfs(1); for(i=1;i<=n;i++) if(siz[i]>m) ans=max(ans,f[i]); printf("%.10f",ans); return 0; }
【BZOJ4726】[POI2017]Sabota? 树形DP
标签:poi == ext printf 公司 16px 一个人 name 而且
原文地址:http://www.cnblogs.com/CQzhangyu/p/6819554.html