牛牛选路径
牛牛选路径
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);
}