某个公司有n个人, 上下级关系构成了一个有根树。其中有个人是叛徒(这个人不知道是谁)。对于一个人, 如果他
下属(直接或者间接, 不包括他自己)中叛徒占的比例超过x,那么这个人也会变成叛徒,并且他的所有下属都会变
成叛徒。你要求出一个最小的x,使得最坏情况下,叛徒的个数不会超过k。
标签:dig oid 1.0 自己 tchar NPU get void 最小值
找点概率期望的题做一做
第一眼肯定是二分想法。但是好像不是很会贪心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\n",ans); 40 return 0; 41 }
END
【树形dp】bzoj4726: [POI2017]Sabota?
标签:dig oid 1.0 自己 tchar NPU get void 最小值
原文地址:https://www.cnblogs.com/antiquality/p/9820984.html