[BZOJ 3573] 米特运输
Link:
Solution:
一道语文题
转化后的题意就是使得每个节点的权值都等于 父亲节点的权值/儿子数 的最小操作数
能发现一条重要的性质:只要一个节点确定,所有节点的权值都确定了
于是我们只要枚举$1……n$每个节点权值不变,
算出根节点$root$的权值出现过的最多次数$res$,用$n-res$即是结果
但如果$O(n^2)$枚举不仅TLE,而且会爆精度
于是我们将权值都用$log$来表示:
(1)算出当根节点$root$为“单位一”:$log(1)$时,各个节点的权值$t_i$
(2)对于节点$v$,$t_v*log(原权值)$就能算出此时根节点在$log$下的权值,接着统计即可
Code:
#include <bits/stdc++.h> using namespace std; const int MAXN=5e5+10; const double eps=1e-6; double t[MAXN],top[MAXN]; int n,dat[MAXN],siz[MAXN]; vector<int> G[MAXN]; void dfs(int x,int anc) { for(int i=0;i<G[x].size();i++) { int v=G[x][i]; if(v==anc) continue; t[v]=t[x]+log(siz[x]);dfs(v,x); } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&dat[i]); for(int i=1;i<n;i++) { int x,y;scanf("%d%d",&x,&y); G[x].push_back(y);G[y].push_back(x); siz[x]++;siz[y]++; } for(int i=2;i<=n;i++) siz[i]--; t[1]=log(1);dfs(1,0); for(int i=1;i<=n;i++) top[i]=t[i]+log(dat[i]); sort(top+1,top+n+1); int res=0,cur=1; for(int i=2;i<=n;i++) if(top[i]-top[i-1]<eps) cur++; else res=max(res,cur),cur=1; res=max(res,cur); printf("%d",n-res); return 0; }
Review:
1、出现只涉及比较,但不用输出确切值的高精度问题时,
使用$log$或$hash$即可,不用高精度类
2、“单位一”的使用
这里的“单位一”用得很妙啊,
如果每次只要乘上相应倍数即可$O(1)$得解,可以用“单位一”的思想先预处理