1401D. Maximum Distributed Tree(dfs+贪心)

传送门哎

∑ 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=1n1j=i+1nf(i,j)

主 要 是 这 个 东 西 很 微 妙 主要是这个东西很微妙 西

怎 么 直 接 来 计 算 每 条 边 被 走 了 几 次 ? 怎么直接来计算每条边被走了几次? ?

现 在 有 一 条 u − v 的 边 , 去 掉 这 条 边 , 分 成 包 含 u 和 包 含 v 的 两 个 集 合 现在有一条u-v的边,去掉这条边,分成包含u和包含v的两个集合 uv,,uv

一 个 集 合 的 一 个 点 q 到 另 一 个 集 合 的 w 都 会 经 过 这 条 边 一个集合的一个点q到另一个集合的w都会经过这条边 qw

如 果 q > w 也 没 关 系 , 那 就 是 w − > q 的 路 上 经 过 这 条 边 如果q>w也没关系,那就是w->q的路上经过这条边 q>w,w>q

所 以 这 条 边 被 经 过 了 s i z e [ v ] ∗ ( n − s i z e [ v ] ) 次 所以这条边被经过了size[v]*(n-size[v])次 size[v](nsize[v])

根 据 这 个 一 遍 d f s 现 在 得 出 了 数 组 a 保 存 每 条 边 经 过 几 次 根据这个一遍dfs现在得出了数组a保存每条边经过几次 dfsa

假设m<=n-1

由 于 让 1 最 少 , 所 以 这 m 个 质 因 子 肯 定 全 选 由于让1最少,所以这m个质因子肯定全选 1,m

贪 心 的 原 则 , 经 过 边 大 的 肯 定 分 配 权 值 大 的 , 分 配 完 了 只 能 分 配 1 了 贪心的原则,经过边大的肯定分配权值大的,分配完了只能分配1了 ,,1

假设m>=n-1

让1最少就是不选1

那 么 贪 心 的 让 [ n − 1 , m ] 的 质 因 子 合 并 成 一 个 超 级 大 的 质 因 子 那么贪心的让[n-1,m]的质因子合并成一个超级大的质因子 [n1,m]

然 后 一 一 匹 配 然后一一匹配

注意事项

s i z [ ] 数 组 不 要 取 模 , 后 续 要 排 序 贪 心 的 siz[]数组不要取模,后续要排序贪心的 siz[],

边 只 有 n − 1 条 , 注 意 和 p 数 组 配 对 的 情 况 边只有n-1条,注意和p数组配对的情况 n1,p

#include 
using namespace std;
#define int long long
const int maxn=5e5+10; 
const int mod=1e9+7;
int t,n,p[maxn],a[maxn],siz[maxn],m;
struct edge{
	int to,nxt;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v){
	d[++cnt]=(edge){v,head[u]},head[u]=cnt;
}
void dfs(int u,int fa)
{
	siz[u]=1;
	for(int i=head[u];i;i=d[i].nxt)
	{
		int v=d[i].to;
		if( v==fa )	continue;
		dfs(v,u);
		siz[u]+=siz[v];
		a[i/2]=siz[v]*(n-siz[v]);
	}
}
signed main()
{
	cin >> t;
	while( t-- )
	{
		cnt=1;
		cin >> n;
		for(int i=1;i> m;
		for(int i=1;i<=m;i++)	cin >> p[i];
		sort(p+1,p+1+m);
		sort(a+1,a+n);
		int ans=0;
		if( m<=n-1 )
		{
			for(int i=n-1,j=m;j>=1;i--,j--)
				ans = (ans+a[i]*p[j]%mod )%mod;
			for(int i=n-m-1;i>=1;i--)
				ans=(ans+a[i])%mod;
			cout << ans << endl;
		}
		else
		{
			for(int i=m-1;i>=n-1;i--)
				p[i]=p[i]*p[i+1]%mod;
			for(int i=n-1;i>=1;i--)
				ans=(ans+a[i]*p[i]%mod )%mod;
			cout << ans << '\n';
		}
		for(int i=0;i<=n*2;i++)	head[i]=0,siz[i]=0;
		for(int i=1;i<=m;i++)	p[i]=0;
	}
}

你可能感兴趣的:(div题解)