首页 > 代码库 > bzoj4726【POI2017】Sabota?

bzoj4726【POI2017】Sabota?

首先可以推出来如果i没有带头叛变,那么i的父亲也一定不会带头叛变,证明显然

所以最劣情况初始的叛徒肯定是叶子,并且带头叛变的人一定是从某个叶子往上走一条链

f[i]表示i不带头叛变的话最小的x

那么我们对所有子树大小>k的f值取max即是答案

f[i]=max j为i的儿子 (min(f[j],siz[j]/(siz[i]-1))

因为对于i的一个儿子j,假如i因为j的子树里的叛徒比例大于x而带头叛变,那么既要满足x<=(j的子树大小占i的子树大小的比例),还要满足j带头叛变即x<=f[j],所以对两个量取min

那么如果i不叛变,那么就不能满足任意一个条件,所以对所有的取max

对于叶子,f[i]=1,因为不管怎样叶子本身就是叛徒,可以视为不需要条件就可以带头叛变,即只有当x>1时才不会叛变

某神犇博客:http://blog.csdn.net/neither_nor/article/details/53373065

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int Mx=500010;
int n,k,tot,head[Mx],next[Mx],ver[Mx],siz[Mx];
double f[Mx],ans;
inline void add(int x,int y)
{  
    next[++tot]=head[x];
    ver[tot]=y;
    head[x]=tot;  
}
void dfs(int x)
{
    siz[x]=1;  
    for(int i=head[x];i;i=next[i])
    {  
        int y=ver[i];  
        dfs(y);  
        siz[x]+=siz[y];  
    }  
    if(!head[x]) f[x]=1; 
    if(head[x]) 
        for(int i=head[x];i;i=next[i])
            { int y=ver[i];f[x]=max(f[x],min(1.0*siz[y]/(siz[x]-1),f[y])); }
    if(siz[x]>k) ans=max(ans,f[x]);
}  
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=2;i<=n;i++)
    {
        int a;scanf("%d",&a);
        add(a,i);
    }
    dfs(1);  
    printf("%.8lf\n",ans); 
    return 0;
} 

 

bzoj4726【POI2017】Sabota?