牛牛选路径
牛牛选路径
https://ac.nowcoder.com/acm/contest/11183/E
牛牛选路径
约定:称度数为奇数的点为奇点,称度数为偶数的点为偶点。
贪心策略:
对于每一个连通块,考虑以下两种情况:
- 
如果不存在奇点,则选择点权最小的点作为头尾连接一条路径。
 - 
存在奇点,则必然有偶数个奇点,只需要选出这些奇点之间的最优匹配,
而这个最优匹配就是:排序之后不断取最小值和最大值匹配。
 
证明:
- 
没有奇点时,可以直接提取一条欧拉回路。
 - 
存在奇点时,对于任何一个合法的匹配,均存在方案,使得以匹配为头尾的链组,将每条边覆盖奇数次。
下面给出了一个合法的构造:
- 
设匹配点集合为,在之间连接一条虚边,记为,得到新图。
容易在原图上找到某一条之间的路径,记作。
 - 
在上求一个欧拉回路,
此时容易通过将替换为的操作将虚边实化,称实化的路径为额外路径,记实化的环为。
 - 
对于每一个,其对应的路径为删除这一段,容易发现路径的头尾是对应的。
此时,上的额外路径均比其他路径少被遍历了恰好一次(因为在其对应的这里被删除了)。
 - 
如果上的非额外路径被遍历了偶数次,则在某一条路径中,额外增加一段绕过一整个的段。
 
这样就保证了上的非额外路径被遍历了奇数次;而额外路径被遍历了偶数次,不产生贡献;
而上的非额外路径就对应了原图的所有边,故构造合法。
 - 
 - 
匹配的最优性:
设排序之后的奇点点权为,容易由排序不等式得到证明:
- 
如果有一个匹配,满足,那么就必然存在一个匹配满足。
由二元排序不等式,此时交换总更优。
 - 
排除的情况后,此时问题变成了对于每个,匹配一个。
那么可以直接分成两个集合,由多元排序不等式得到最优解。
 
 - 
 
#include<bits/stdc++.h>
using namespace std;
#define M 100005
#define P 998244353 
int n,m,a[M],deg[M],sk[M];
vector<int>d[M];
bool cmp(int x,int y){
	return a[x]<a[y];	
}
int main(){
	int mx=0;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
	}
	for(int i=1,x,y;i<=m;++i){
		scanf("%d%d",&x,&y);
		d[x].push_back(y);
		d[y].push_back(x);
		deg[x]^=1;deg[y]^=1;
	}
	int cnt=0,ans=0;
	for(int i=1;i<=n;++i)if(deg[i])sk[++cnt]=i;
	if(cnt==0){
		ans=1e9;
		for(int i=1;i<=n;++i)ans=min(ans,a[i]*a[i]);
	}else{
		sort(sk+1,sk+cnt+1,cmp);
		for(int i=1;i<=cnt/2;++i)ans+=a[sk[i]]*a[sk[cnt-i+1]];
	}
	printf("%d",ans%P);
}


