【题解】CF1401D
题目链接
解题思路
对于每一条边,其贡献为断开它后两部分的siz的乘积乘以边权。所以我们对于每一个siz的乘积排序,对p排序,小的对小的,大的对大的,最大的将剩下所有全拿走即可。
其中siz在树上DFS求
代码
#include<bits/stdc++.h>
using namespace std;
const int Mod=1e9+7;
const int inf=1e9+7;
int t;
int head[200005];
int p[200005];
struct e{
int to,nxt;
}edge[400005];
int tot=0;
long long ctr[200005];
void add_edge(int u,int v){
tot++;
edge[tot].nxt=head[u];
edge[tot].to=v;
head[u]=tot;
}
long long siz[200005];
void DFS(int now,int father){
int nxtt;
siz[now]=1;
for(int i=head[now];i;i=edge[i].nxt){
nxtt=edge[i].to;
if(nxtt==father)continue;
DFS(nxtt,now);
siz[now]+=siz[nxtt];
}
return ;
}
long long n;
int main(){
scanf("%d",&t);
for(int cas=1;cas<=t;cas++){
tot=0;
for(int i=1;i<=n;i++){
head[i]=0,siz[i]=0,ctr[i]=0;
}
scanf("%lld",&n);
int u,v;
for(int i=1;i<=n-1;i++){
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
DFS(1,0);
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&p[i]);
}
for(int i=1;i<=n;i++){
ctr[i]=siz[i]*(n-siz[i]);
}
sort(ctr+1,ctr+1+n);
sort(p+1,p+1+m);
//注意!!!切不可在sort前取摸
for(int i=1;i<=n;i++)ctr[i]%=Mod;
long long ans=0;
if(m>=n){
for(int i=2;i<=n-1;i++){
ans+=ctr[i]*p[i-1];
ans%=Mod;
}
long long mcon=1;
for(int i=n-1;i<=m;i++){
mcon*=p[i];
mcon%=Mod;
}
ans+=ctr[n]%Mod*mcon%Mod;
ans%=Mod;
printf("%lld\n",ans);
}else{
int arr=m;
for(int i=n;i>=2;i--){
if(arr>0){
ans+=ctr[i]*p[arr];
arr--;
ans%=Mod;
}else{
ans+=ctr[i];
ans%=Mod;
}
}
printf("%lld\n",ans);
}
}
return 0;
}
本文链接:http://kaispace.com.cn/index.php/archives/702/
如果未注明出处,复制公开后需将注明本博客链接。打赏作者