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;
}
posted @ 2021-05-31 19:46  u_yan  阅读(27)  评论(0编辑  收藏  举报