Codeforces Round #665 (Div. 2) D. Maximum Distributed Tree ###K ###K //K
题目链接:https://codeforces.ml/contest/1401/problem/D
题意:给每条边标记一个数,要求用的1尽量少,并且乘积之和为k 要求的是 1 到2 3……n , 2到 3,4…… n n-1到n 的简单路径经过的边上的数字和
思路: 求出每条边走过的次数,然后贪心的让最多的边和最大的数相乘 如何o(n) 求出每条边被走过的次数呢
考虑一条边的上下两个部分,上部分的任意点都要走到下部分的任意点, 并且因为有大小关系,每对点只有走一次 那么cnt=size[u]*(n-size[u]) size为该点的子树节点
用点表示边, 每个点代表他连着的上面的边, 所以1没有边 即2~n n-1条边
然后讨论 m>n-1的情况 和m<=n-1的情况 前者要将多余的前几个数 乘在一起即为最大
还有就是sort 的时候 用greater<int>的话 只会对内部int类型的排序, 用ll 记得写greater<ll>
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 const int mod=1e9+7; 5 #define ll long long 6 #define pi pair<int,int> 7 #define fi first 8 #define sc second 9 #define pb push_back 10 vector<int>E[maxn]; 11 ll p[maxn]; 12 ll cnt[maxn]; 13 int n; 14 vector<ll>ed; 15 16 void dfs(int u,int fa) 17 { 18 cnt[u]=1; 19 for(auto &v:E[u]) 20 { 21 if(v==fa) continue; 22 dfs(v,u); 23 cnt[u]+=cnt[v]; 24 } 25 if(u!=1) ed.pb(cnt[u]*(n-cnt[u])); 26 } 27 28 29 int main() 30 { 31 ios::sync_with_stdio(0); 32 cin.tie(0); 33 int t; 34 cin>>t; 35 while(t--) 36 { 37 cin>>n; 38 for(int i=1;i<=n;i++) E[i].clear(); 39 for(int i=1;i<n;i++) 40 { 41 int x,y; 42 cin>>x>>y; 43 E[x].pb(y); 44 E[y].pb(x); 45 } 46 ed.clear(); 47 int m; 48 cin>>m; 49 for(int i=1;i<=m;i++) cin>>p[i]; 50 dfs(1,0); 51 vector<ll>eqq; 52 sort(p+1,p+1+m,greater<ll>()); 53 sort(ed.begin(),ed.end(),greater<ll>()); 54 int pos=m-(n-1)+1; 55 ll mul=1; 56 for(int i=1;i<=pos;i++) 57 { 58 mul*=p[i],mul%=mod; 59 } 60 if(pos>=1) eqq.pb(mul); 61 pos=max(pos,0); 62 for(int i=pos+1;i<=m;i++) eqq.pb(p[i]); 63 while((int)eqq.size()<n-1) eqq.pb(1); 64 ll ans=0; 65 for(int i=0;i<n-1;i++) 66 ans=(ans+ed[i]%mod*eqq[i]%mod)%mod; 67 cout<<ans<<'\n'; 68 69 } 70 71 72 73 74 75 }

浙公网安备 33010602011771号