CF1401D Maximum Distributed Tree
- 题意:\(f(i, j)\) 代表了从 \(i\) 到 \(j\) 的简单路径边权和。要求构造给定树的边权使得 \(\sum_{i=1}^{n} \sum_{j = i}^{n}f(i, j)\) 最大。
- 题解:设一条边为 \(<u, v>\) 然后设 \(cnt_u\) 为节点 \(u\) 的子节点的数量,首先自己想到的就是 \(dfs\) 处理一遍就行。可知每条边的权重对答案贡献为 \(cnt_u \times cnt_v \times w_e\),然后分配 \(m\) 个质数给 \(w\) 就行了。但是很显然如果质数数量小于 \(n\) 那么就是直接用大的向小的给他们乘。然后如果素数数量大于 \(n-1\) 那么就考虑如何搞,假设把大的给大的乘,然后,设 \(k_1,k_2,k_3\) 为素数,且 \(k_1 > k_2 > k_3\) 并且 \(sum_1 > sum_2 > sum_3\)。得出不等式:
\[k_1 \times k_3 \times sum_1 + k_2\times sum_2 < k_1 \times k_2 \times sum_1 + k_3\times sum_2
\]
\[k_1\times sum_1\times(k_3 - k_2) < sum_2\times(k_2 - k_3)
\]
很显然 \(k_3 > k_2\)等式左边小于零,右边大于零,所以等式成立。
所以以后贪心最好用不等式证明一下正确性。
- 代码:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 1e6 + 9;
const ll mod = 1e9 + 7;
vector<ll> G[N];
vector<ll> cnt_edge;
vector<ll> tem;
ll cnt[N];
ll n;
void dfs(int u, int fa) {
bool f = 0;
for (auto v : G[u]) {
if (v == fa) continue;
dfs(v, u);
cnt[u] += cnt[v];
}
if (fa != -1)
cnt_edge.push_back(cnt[u] * (n * 1ll - cnt[u]));
}
void solve() {
scanf("%lld", &n);
cnt[n] = 1;
for (int i = 1; i < n; i++) {
ll u, v;
scanf("%lld%lld", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
cnt[i] = 1;
}
dfs(1, -1);
sort(cnt_edge.begin(), cnt_edge.end());
reverse(cnt_edge.begin(), cnt_edge.end());
ll m;
scanf("%lld", &m);
ll ans = 0;
for (ll i = 1; i <= m; i++) {
ll x;
scanf("%lld", &x);
tem.push_back(x);
}
sort(tem.begin(), tem.end());
for (int i = 0; i < tem.size(); i ++) {
tem[i] %= mod;
}
while (tem.size() > cnt_edge.size()) {
ll x = tem[tem.size()-1];
(x *= tem[tem.size() - 2]) %= mod;
tem[tem.size() - 2] = x;
tem.pop_back();
}
reverse(tem.begin(), tem.end());
while (tem.size() < cnt_edge.size()) {
tem.push_back(1);
}
for (ll i = 0; i < cnt_edge.size(); i++) {
(ans += cnt_edge[i] * tem[i] % mod) %= mod;
}
printf("%lld\n", ans);
tem.clear();
cnt_edge.clear();
for (ll i = 1; i <= n; i++) G[i].clear();
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
ll n;
scanf("%lld", &n);
while (n--) {
solve();
}
return 0;
}