Luogu P3237 [HNOI2014] 米特运输 题解 [ 蓝 ] [ 树形 DP ] [ 哈希 ]
不是很难,但是思路很巧妙的一道题。
手模样例,观察合法方案的性质,容易发现,只要有一个节点权值是固定的,那么整棵树所有节点的权值便也固定了。
而由于每个节点之间是倍数关系,因此我们需要一个基本单位来表示倍数关系。为了方便,我们直接将权值的最大值,即根节点的权值设为基本单位,那么其余节点的系数一定形如 \(\dfrac{1}{k}\)。
在得到每个节点的系数后,假设当前节点的权值为 \(x\),那么当 \(kx = a_{root}\) 的时候这两个节点的权值所对应的合法方案是一样的。
由此可以想到记录每个节点的 \(k\) 值,然后乘上该点的原权值,丢进一个桶里,桶中最多的权值即为最终选择的权值。
因为 \(k\) 可能很大,因此需要采用哈希的思想存储。使用 map 实现桶,时间复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 500005;
const ll mod = 998442353;
int n;
ll a[N], b[N], ans;
map<ll, ll> tot;
vector<int> g[N];
void dfs(int u, int fa)
{
if(u == 1) b[u] = 1;
else if(fa == 1) b[u] = g[1].size();
else b[u] = (b[fa] * (g[fa].size() - 1)) % mod;
for(auto v : g[u])
{
if(v == fa) continue;
dfs(v, u);
}
tot[(a[u] * b[u]) % mod]++;
ans = max(ans, tot[(a[u] * b[u]) % mod]);
}
int main()
{
//freopen("sample.in", "r", stdin);
//freopen("sample.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1, 0);
cout << n - ans;
return 0;
}

浙公网安备 33010602011771号