Maximum Distributed Tree CodeForces - 1401D

原题链接
考察:贪心+思维
思路:
  说是D题,思路比C题明显,很明显经过次数最多的边赋最大的值,虽然是构造但思路非常明显.
  难点是怎么计算经过每条边的次数(本蒟蒻就卡这了菜是原罪),经过查看题解观察可得对于一条边(u,v),有sz[v](v点以及v的子节点)个点会经过v到达u或者u以上的点,两两配对的方案数是sz[v]*(n-sz[v]).因为每个点标号一定不同,所以一定存在一个>一个<.

  说一下我WA了8次的坑点,计算经过次数不能%,否则排序后计算的式子就与原来不一样.

Code

#include <iostream> 
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 200010,M = 60010,Mod=1e9+7;
struct Road{
	int to,ne;
}road[N<<1];
int idx,n,prime[M],m,sz[N],h[N],cnt;
LL sum[N<<1];
void add(int a,int b)
{
	road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
void init()
{
	cnt = idx = 0;
	memset(sz,0,sizeof sz);
	memset(h,-1,sizeof h);
}
int dfs(int u,int fa)
{
	sz[u] = 1;
	for(int i=h[u];~i;i=road[i].ne)
	{
		int v = road[i].to;
		if(v==fa) continue;
		sz[u]+=dfs(v,u);
		sum[++cnt] = (LL)sz[v]*(n-sz[v]);
	}//WA n次:sum不能%Mod 
	return sz[u];
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		init();
		for(int i=1;i<n;i++)
		{
			int a,b; 
			scanf("%d%d",&a,&b);
			add(a,b); add(b,a);
		}
		scanf("%d",&m);
		prime[0] =1;
		for(int i=1;i<=m;i++) scanf("%d",&prime[i]);
		sort(prime+1,prime+m+1);
		dfs(1,-1);
		sort(sum+1,sum+cnt+1);
		int res = 0;
		if(cnt<m)
		{
			for(int i=m;i>cnt;i--)
			 prime[cnt] = (LL)prime[cnt]*prime[i]%Mod;
			m = cnt;
		}
		for(int i=cnt,j=m;i>=1;i--,j--)
		{
			if(j<0) j = 0;
			res+=(LL)sum[i]*prime[j]%Mod;
			res%=Mod;
		}
		printf("%d\n",res);
	}
	return 0;
}

posted @ 2021-06-02 14:08  acmloser  阅读(30)  评论(0编辑  收藏  举报