D. Maximum Distributed Tree
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a tree that consists of nn nodes. You should label each of its n−1n−1 edges with an integer in such way that satisfies the following conditions:
- each integer must be greater than 00;
- the product of all n−1n−1 numbers should be equal to kk;
- the number of 11-s among all n−1n−1 integers must be minimum possible.
Let's define f(u,v)f(u,v) as the sum of the numbers on the simple path from node uu to node vv. Also, let ∑i=1n−1∑j=i+1nf(i,j)∑i=1n−1∑j=i+1nf(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 109+7109+7.
In this problem, since the number kk can be large, the result of the prime factorization of kk is given instead.
Input
The first line contains one integer tt (1≤t≤1001≤t≤100) — the number of test cases.
The first line of each test case contains a single integer nn (2≤n≤1052≤n≤105) — the number of nodes in the tree.
Each of the next n−1n−1 lines describes an edge: the ii-th line contains two integers uiui and vivi (1≤ui,vi≤n1≤ui,vi≤n; ui≠viui≠vi) — indices of vertices connected by the ii-th edge.
Next line contains a single integer mm (1≤m≤6⋅1041≤m≤6⋅104) — the number of prime factors of kk.
Next line contains mm prime numbers p1,p2,…,pmp1,p2,…,pm (2≤pi<6⋅1042≤pi<6⋅104) such that k=p1⋅p2⋅…⋅pmk=p1⋅p2⋅…⋅pm.
It is guaranteed that the sum of nn over all test cases doesn't exceed 105105, the sum of mm over all test cases doesn't exceed 6⋅1046⋅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 109+7109+7.
Example
input
Copy
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
output
Copy
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)=1f(1,2)=1, f(1,3)=3f(1,3)=3, f(1,4)=5f(1,4)=5, f(2,3)=2f(2,3)=2, f(2,4)=4f(2,4)=4, f(3,4)=2f(3,4)=2, so the sum of these 66 numbers is 1717.
In the second test case, one of the optimal ways is on the following image:
In this case, f(1,2)=3f(1,2)=3, f(1,3)=1f(1,3)=1, f(1,4)=4f(1,4)=4, f(2,3)=2f(2,3)=2, f(2,4)=5f(2,4)=5, f(3,4)=3f(3,4)=3, so the sum of these 66 numbers is 1818.
=========================================================================
突破点就在于每条边实际的贡献,这里有一个套路或者说非常重要的结论就是 图或者树中一条边被经过的次数等于这条边两侧点数的乘积。特别的,在树上考虑的时候,只需要考虑每个非根节点的儿子个数与 n-儿子个数的乘积即可,这样就获得了n-1个点代表的n-1条边的实际贡献,接下来就是一个分配的贪心问题了。
当m<=n-1时,也就是我们未来满足第三个条件“1个数必须足够少”,那么就尽量把这m个数一一对应的分配,显然大的配对大的。
m>n-1时,我们可以做到没有1出现,那么就不让他出现1,考虑把前m-(n-1)个最大的因子都怼到贡献最大的那条边上,注意是因子乘积,否则能过样例不能过test 2
# include<bits/stdc++.h>
using namespace std;
# define mod 1000000007
typedef long long int ll;
vector<int>v[100000+10];
ll sizeson[100000+10],temp[100000+10],a[100000+10];
int len=0,n;
void dfs(int now,int pre)
{
sizeson[now]=1;
for(auto it:v[now])
{
if(it==pre)
continue;
dfs(it,now);
sizeson[now]+=sizeson[it];
}
if(now!=1)
{
len++;
temp[len]=(n-sizeson[now])*sizeson[now];
}
}
bool cmp(ll x,ll y)
{
return x>y;
}
int main ()
{
int t;
cin>>t;
while(t--)
{
cin>>n;
len=0;
for(int i=1;i<=n;i++)
{
v[i].clear();
}
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
v[x].push_back(y);
v[y].push_back(x);
}
int m;
cin>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i];
}
dfs(1,0);
if(m<=len)
{
sort(temp+1,temp+len+1,cmp);
sort(a+1,a+1+m,cmp);
ll ans=0;
for(int i=1;i<=len;i++)
{
if(i>m)
{
ans+=temp[i];
ans%=mod;
}
else
{
ll fuck=temp[i]*a[i]%mod;
ans+=fuck;
ans%=mod;
}
}
cout<<ans<<endl;
}
else
{
//留出来len-1个给小边 ,剩下m-(len-1)个全部给最大的
sort(temp+1,temp+len+1,cmp);
sort(a+1,a+1+m,cmp);
ll ans=0,fuck=1;
for(int i=1;i<=m-(len-1);i++)
{
fuck*=a[i];
fuck%=mod;
}
// cout<<m-(len-1)<<" **** "<<endl;
fuck*=temp[1];
fuck%=mod;
ans=fuck;
int now=2;
for(int i=m-(len-1)+1;i<=m;i++)
{
fuck=temp[now]*a[i]%mod;
ans+=fuck;
ans%=mod;
now++;
}
cout<<ans<<endl;
}
}
return 0;
}