[题解]ABC282E Choose Two and Eat One

ABC282E Choose Two and Eat One

又一个图论的回顾——Kruskal最小(最大)生成树算法。

看到\(n\)的范围只有\(500\),应该没有什么特别的算法。那么我们考虑建一个*\(n\)个顶点的完全图,节点\(x\)到节点\(y\)的边权值就是\(x^y+y^x\)。然后跑一遍最大生成树,得到的和就是最大结果了。

如何证明生成树的边一定满足题目条件?因为一共要吃掉\(n-1\)个球,也就是删除图上的\(n-1\)条边,若想让这\(n-1\)条边连接\(n\)个点,必须要求这些边构成一个树。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct edge{
	int u,v,w;
}edges[250010];
int n,m,a[510],fa[510],cnt;
bool cmp(edge a,edge b){return a.w>b.w;}
int find(int x){
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
int qpow(int a,int b){
	int fac=1;
	while(b){
		if(b&1) fac=(fac*a)%m;
		a=(a*a)%m,b>>=1;
	}
	return fac;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			edges[++cnt].u=i,edges[cnt].v=j;
			edges[cnt].w=(qpow(a[i],a[j])+qpow(a[j],a[i]))%m;
		}
	}
	sort(edges+1,edges+1+cnt,cmp);
	for(int i=1;i<=n;i++) fa[i]=i;
	int edgecnt=0,ans=0;
	for(int i=1;i<=cnt;i++){
		int u=find(edges[i].u),v=find(edges[i].v);
		if(u==v) continue;
		fa[u]=v;
		edgecnt++;
		ans+=edges[i].w;
		if(edgecnt>=n-1) break;
	}
	cout<<ans;
	return 0;
}
posted @ 2024-04-18 22:33  Sinktank  阅读(13)  评论(0编辑  收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2024 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.