1. 程式人生 > >BZOJ3573 [Hnoi2014]米特運輸 【貪心】

BZOJ3573 [Hnoi2014]米特運輸 【貪心】

保留 clas pan size cst () log getch sin

題目鏈接

BZOJ3573

題解

題目又臭又長系列

題意:修改盡量少的點權,使得:
①同個節點的所有兒子點權相同
②任意非葉節點權值等於其兒子權值之和

容易發現一旦任意一個點權值確定,整棵樹權值就確定
一個比較簡單的想法是枚舉根節點權值

但我們可以通過計算出每個節點如若保留原值,根節點會是什麽值
如果兩個節點能同時不變,當且僅當它們對應根節點權值相等
我們算出來排序選擇權值最多的那一個就好了
直接乘會爆\(long long\),可使用\(log\)轉化為加法

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio> #include<cmath> #include<map> #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) make_pair<int,int>(a,b) #define cls(s) memset(s,0,sizeof(s)) #define cp pair<int,int> #define LL long long int
#define eps 1e-9 using namespace std; const int maxn = 500005,maxm = 1000005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1
) + c - 48; c = getchar();} return out * flag; } int tot; double H[maxn]; int n,val[maxn],de[maxn]; int h[maxn],ne = 1; struct EDGE{int to,nxt;}ed[maxm]; inline void build(int u,int v){ ed[++ne] = (EDGE){v,h[u]}; h[u] = ne; ed[++ne] = (EDGE){u,h[v]}; h[v] = ne; de[u]++; de[v]++; } double v[maxn]; int fa[maxn]; void dfs(int u){ if (u == 1) v[u] = log(1); else v[u] = v[fa[u]] + log(fa[u] == 1 ? de[fa[u]] : de[fa[u]] - 1); H[++tot] = v[u] + log(val[u]); Redge(u) if ((to = ed[k].to) != fa[u]){ fa[to] = u; dfs(to); } } int main(){ n = read(); REP(i,n) val[i] = read(); for (int i = 1; i < n; i++) build(read(),read()); dfs(1); int ans = 0,cnt = 0; sort(H + 1,H + 1 + tot); for (int i = 1; i <= tot; i++){ if (fabs(H[i] - H[i - 1]) > eps) ans = max(ans,cnt),cnt = 1; else cnt++; } ans = max(ans,cnt); printf("%d\n",n - ans); return 0; }

BZOJ3573 [Hnoi2014]米特運輸 【貪心】