Description
某个公司有n个人, 上下级关系构成了一个有根树。其中有个人是叛徒(这个人不知道是谁)。对于一个人, 如果他
下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变
成叛徒。你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。
Input
第一行包含两个正整数n,k(1<=k<=n<=500000)。
接下来n-1行,第i行包含一个正整数p[i+1],表示i+1的父亲是pi+1。
Output
输出一行一个实数x,误差在10^-6以内都被认为是正确的。
Sample Input
9 3
1
1
2
2
2
3
7
3
Sample Output
0.6666666667
HINT
答案中的x实际上是一个无限趋近于2/3但是小于2/3的数
因为当x取2/3时,最坏情况下3,7,8,9都是叛徒,超过了k=3。
分析:
一开始二分答案,看一下时限巨稳,结果就TLE了。
考虑dp。设
f
[
i
]
f[i]
f[i]表示以
i
i
i不被变成叛徒的最小
x
x
x(也是
i
i
i变成叛徒的最大
x
x
x)。
因为一开始只有一个叛徒,所以只可能是某一个儿子使他变成叛徒(因为可以把当前点变为叛徒,儿子一定也能变成叛徒)。当前点变成叛徒,要同时满足儿子变成叛徒,且儿子的个数足够把当前点变成叛徒。
因为要考虑最坏情况,所以所有儿子取max。所以
f
[
i
]
=
m
a
x
(
f
[
i
]
,
m
i
n
(
f
[
j
]
,
s
i
z
e
[
j
]
/
(
s
i
z
e
[
i
]
−
1
)
)
)
f[i]=max(f[i],min(f[j],size[j]/(size[i]-1)))
f[i]=max(f[i],min(f[j],size[j]/(size[i]−1)))
代码:
/**************************************************************
Problem: 4726
User: ypxrain
Language: C++
Result: Accepted
Time:9784 ms
Memory:32468 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=5e5+7;
using namespace std;
int n,k,x,cnt;
int ls[maxn],size[maxn];
double f[maxn];
struct edge{
int y,next;
}g[maxn];
void add(int x,int y)
{
g[++cnt]=(edge){y,ls[x]};
ls[x]=cnt;
}
void dfs(int x)
{
size[x]=1;
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
dfs(y);
size[x]+=size[y];
}
}
void dp(int x)
{
if (size[x]==1)
{
f[x]=1;
return;
}
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
dp(y);
f[x]=max(f[x],min(f[y],(double)size[y]/((double)size[x]-1)));
}
}
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
scanf("%d%d",&n,&k);
for (int i=2;i<=n;i++)
{
scanf("%d",&x);
add(x,i);
}
dfs(1);
dp(1);
double ans=0;
for (int i=1;i<=n;i++) if (size[i]>k) ans=max(ans,f[i]);
printf("%.7lf",ans);
}