Title
CodeForces 1401 D. Maximum Distributed Tree
Time Limit
2 seconds
Memory Limit
256 megabytes
Problem Description
You are given a tree that consists of n n n nodes. You should label each of its n − 1 n-1 n−1 edges with an integer in such way that satisfies the following conditions:
Let’s define f ( u , v ) f(u,v) f(u,v) as the sum of the numbers on the simple path from node u u u to node v v v. Also, let ∑ i = 1 n − 1 ∑ j = i + 1 n f ( i , j ) \sum\limits_{i=1}^{n-1} \sum\limits_{j=i+1}^n f(i,j) i=1∑n−1j=i+1∑nf(i,j) be a distribution index of the tree.
Find the maximum possible distribution index you can get. Since answer can be too large, print it modulo 1 0 9 + 7 10^9 + 7 109+7.
In this problem, since the number k k k can be large, the result of the prime factorization of k k k is given instead.
Input
The first line contains one integer t t t ( 1 ≤ t ≤ 100 1 \le t \le 100 1≤t≤100) — the number of test cases.
The first line of each test case contains a single integer n n n ( 2 ≤ n ≤ 1 0 5 2 \le n \le 10^5 2≤n≤105) — the number of nodes in the tree.
Each of the next n − 1 n-1 n−1 lines describes an edge: the i i i-th line contains two integers u i u_i ui and v i v_i vi ( 1 ≤ u i , v i ≤ n 1 \le u_i, v_i \le n 1≤ui,vi≤n; u i ≠ v i u_i \ne v_i ui=vi) — indices of vertices connected by the i i i-th edge.
Next line contains a single integer m m m ( 1 ≤ m ≤ 6 ⋅ 1 0 4 1 \le m \le 6 \cdot 10^4 1≤m≤6⋅104) — the number of prime factors of k k k.
Next line contains m m m prime numbers p 1 , p 2 , … , p m p_1, p_2, \ldots, p_m p1,p2,…,pm ( 2 ≤ p i < 6 ⋅ 1 0 4 2 \le p_i < 6 \cdot 10^4 2≤pi<6⋅104) such that k = p 1 ⋅ p 2 ⋅ … ⋅ p m k = p_1 \cdot p_2 \cdot \ldots \cdot p_m k=p1⋅p2⋅…⋅pm.
It is guaranteed that the sum of n n n over all test cases doesn’t exceed 1 0 5 10^5 105, the sum of m m m over all test cases doesn’t exceed 6 ⋅ 1 0 4 6 \cdot 10^4 6⋅104, and the given edges for each test cases form a tree.
Output
Print the maximum distribution index you can get. Since answer can be too large, print it modulo 1 0 9 + 7 10^9+7 109+7.
Sample Input
3
4
1 2
2 3
3 4
2
2 2
4
3 4
1 3
3 2
2
3 2
7
6 1
2 3
4 6
7 3
5 1
3 6
4
7 5 13 3
Sample Onput
17
18
286
Note
In the first test case, one of the optimal ways is on the following image:
In this case, f ( 1 , 2 ) = 1 f(1,2)=1 f(1,2)=1, f ( 1 , 3 ) = 3 f(1,3)=3 f(1,3)=3, f ( 1 , 4 ) = 5 f(1,4)=5 f(1,4)=5, f ( 2 , 3 ) = 2 f(2,3)=2 f(2,3)=2, f ( 2 , 4 ) = 4 f(2,4)=4 f(2,4)=4, f ( 3 , 4 ) = 2 f(3,4)=2 f(3,4)=2, so the sum of these 6 6 6 numbers is 17 17 17.
In the second test case, one of the optimal ways is on the following image:
In this case, f ( 1 , 2 ) = 3 f(1,2)=3 f(1,2)=3, f ( 1 , 3 ) = 1 f(1,3)=1 f(1,3)=1, f ( 1 , 4 ) = 4 f(1,4)=4 f(1,4)=4, f ( 2 , 3 ) = 2 f(2,3)=2 f(2,3)=2, f ( 2 , 4 ) = 5 f(2,4)=5 f(2,4)=5, f ( 3 , 4 ) = 3 f(3,4)=3 f(3,4)=3, so the sum of these 6 6 6 numbers is 18 18 18.
Source
CodeForces 1401 D. Maximum Distributed Tree
题意
给一棵树 你可以任意分配边权
但要使得所有边权乘积 = = k ==k ==k
k是按质因子形式给出
设 f ( i , j ) f(i,j) f(i,j)是 i i i与 j j j路径边权和。
要使得所有点对边权和 ∑ i = 1 n − 1 ∑ j = i + 1 n f ( i , j ) \sum\limits_{i=1}^{n-1} \sum\limits_{j=i+1}^n f(i,j) i=1∑n−1j=i+1∑nf(i,j)最大。
思路
经典所有点对边权和,对每条边来说贡献就是左边点的个数*右边点的个数。
求出来排个序。
对于 k k k来说
如果他的质因子个数不足 n − 1 n-1 n−1则补 1 1 1即可
如果超过 n − 1 n-1 n−1呢?
则思考两两乘起来合并
是大的两两合并更优(粗略证明
设质因子为 p 0 p 1 p 2 p0 p1 p2 p0p1p2
边数贡献为 c 0 c 1 c0c1 c0c1
均从大到小排序
则 p 0 ∗ c 0 + p 1 ∗ c 0 + p 2 ∗ c 1 > p 0 ∗ c 0 + p 1 ∗ c 1 + p 2 ∗ c 1 p0*c0+p1*c0+p2*c1>p0*c0+p1*c1+p2*c1 p0∗c0+p1∗c0+p2∗c1>p0∗c0+p1∗c1+p2∗c1
则合并即可
最后对应相乘就是答案,别忘了取模 1 0 9 + 7 10^9+7 109+7
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 3e5 + 5;
const ll inf = 0x3f3f3f3f;
const ll mod = 1e9 + 7;
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
void dfs(int now, int fa, vector<vector<int>> &edge, vector<ll> &c,
vector<ll> &sz, int n) {
sz[now] = 1;
for (auto &it : edge[now]) {
if (it == fa) continue;
dfs(it, now, edge, c, sz, n);
sz[now] += sz[it];
}
c.emplace_back(sz[now] * (n - sz[now]));
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<vector<int>> edge(n + 1, vector<int>());
for (int i = 1, u, v; i < n; ++i) {
cin >> u >> v;
edge[u].emplace_back(v);
edge[v].emplace_back(u);
}
int m;
cin >> m;
deque<ll> dq(m);
for (auto &it : dq) cin >> it;
sort(all(dq), greater<ll>());
while (dq.size() > n - 1) {
dq[1] = dq[0] * dq[1] % mod;
dq.pop_front();
}
while (dq.size() < n - 1) dq.push_back(1);
vector<ll> c, sz(n + 1);
dfs(1, 0, edge, c, sz, n);
sort(all(c), greater<ll>());
ll ans = 0;
for (int i = 0; i < n - 1; ++i) {
ans = (ans + c[i] * dq[i] % mod) % mod;
}
cout << ans << endl;
}
return 0;
}