zoukankan      html  css  js  c++  java
  • 【树形dp】bzoj4726: [POI2017]Sabota?

    找点概率期望的题做一做

    Description

    某个公司有n个人, 上下级关系构成了一个有根树。其中有个人是叛徒(这个人不知道是谁)。对于一个人, 如果他
    下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变
    成叛徒。你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。

    Input

    第一行包含两个正整数n,k(1<=k<=n<=500000)。
    接下来n-1行,第i行包含一个正整数p[i+1],表示i+1的父亲是p[i+1](1<=p[i+1]<=i)。

    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。

    题目分析

    第一眼肯定是二分想法。但是好像不是很会贪心check。

    于是干脆考虑dp,从问题反面入手。先丢开叛徒总数的限制,$f[i]$表示$i$这整颗子树没叛变的最小x值。转移就是$f[i]=max{f[i],min{size_j/(size_i-1),f[j]}}$.因为子树$i$叛变的情况需要同时满足:一是子树$j$占比例超过$x$,二是子树$j$也叛变了。那么,最小的$f[i]$只会出现在它们两个的最小值中。又由于所有情况下都要保证子树$i$不叛变,所以$f[i]$这里是取max的。最后统计答案时,就是所有子树$size>k$的最大$f[i]$。

    看题还是不仔细,第一次看成“叛徒个数小于k"WA了一发。

     1 #include<bits/stdc++.h>
     2 const int eps = 1e-10;
     3 const int maxn = 500035;
     4 
     5 int n,k,tot[maxn];
     6 double ans,f[maxn];
     7 std::vector<int> a[maxn];
     8 
     9 int read()
    10 {
    11     char ch = getchar();
    12     int num = 0;
    13     bool fl = 0;
    14     for (; !isdigit(ch); ch = getchar())
    15         if (ch=='-') fl = 1;
    16     for (; isdigit(ch); ch = getchar())
    17         num = (num<<1)+(num<<3)+ch-48;
    18     if (fl) num = -num;
    19     return num;
    20 }
    21 void dfs(int x)
    22 {
    23     tot[x] = 1;
    24     for (int i=0; i<a[x].size(); i++)
    25         dfs(a[x][i]), tot[x] += tot[a[x][i]];
    26     if (tot[x]==1) f[x] = 1;
    27     else{
    28         for (int i=0; i<a[x].size(); i++)
    29             f[x] = std::max(f[x], std::min(f[a[x][i]], 1.0*tot[a[x][i]]/(tot[x]-1)));
    30     }
    31 }
    32 int main()
    33 {
    34     n = read(), k = read();
    35     for (int i=2; i<=n; i++) a[read()].push_back(i);
    36     dfs(1);
    37     for (int i=1; i<=n; i++)
    38         if (tot[i] > k) ans = std::max(ans, f[i]);
    39     printf("%.8lf
    ",ans);
    40     return 0;
    41 }

    END

  • 相关阅读:
    矩阵游戏|ZJOI2007|BZOJ1059|codevs1433|luoguP1129|二分图匹配|匈牙利算法|Elena
    BZOJ3262: 陌上花开
    BZOJ1176: [Balkan2007]Mokia
    BZOJ1261: [SCOI2006]zh_tree
    BZOJ2004: [Hnoi2010]Bus 公交线路
    BZOJ1066: [SCOI2007]蜥蜴
    BZOJ1294: [SCOI2009]围豆豆Bean
    BZOJ2756: [SCOI2012]奇怪的游戏
    BZOJ1857: [Scoi2010]传送带
    BZOJ1237: [SCOI2008]配对
  • 原文地址:https://www.cnblogs.com/antiquality/p/9820984.html
Copyright © 2011-2022 走看看