群论学习笔记
本文有着大量的感性理解。
一、置换
实际上可以理解为对集合的每个元素一个新的标号,满足这个标号集合与原集合一一对应。
如集合 \(X=\{x_1,x_2,\dots,x_n\}\),他的置换就可以表示为:\(\sigma=(_{x_{p_1}\ \ \ x_{p_2}\ \ \ \dots\ \ \ x_{p_n}}^{\ x_1\ \ \ \ \ x_2\ \ \ \dots\ \ \ \ x_n})\)。
做题时通常满足 \(x_i=i\),我们就可以表示为:\(\sigma=x_{p_1}x_{p_2}\dots x_{p_n}\)。
明显会出现循环节,比如 \(\sigma=265431\),此时 \(x_1,x_2,x_6\) 就是一个循环。根据这个特性,我们还可以将置换表示为:\(\sigma=(126)(35)(4)\),单独的循环节可以不写,即可以省略为:\(\sigma=(126)(35)\)。
运用:\(\color{blue}{[POI2009]\ PLO}\)。
考虑可以将交换转化为一个循环节内部的交换,设循环内 \(\sum w_i\) 为 \(sum\),\(\min w_i\) 为 \(min\),循环节的大小为 \(num\),则容易想到一种 \(sum+(num-2)\times min\) 的方案,即从最小值开始交换。
但考虑假如我们先减小循环节最小值,即将全局最小值 \(minn\) 与 \(min\) 交换,再进行上述操作,最后再把 \(min\) 换回来,这样就可以达到 \(sum+min+(num+1)\times minn\) 的代价,两者取 \(\min\) 即可。
时间复杂度 \(O(n)\),其本质等价于置换的循环节式写法。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+5;
int n,ans,minn=2e9,fl[N];
int yc[N],a[N],b[N],w[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>w[i],ans+=w[i];
minn=min(minn,w[i]);
}for(int i=1;i<=n;i++)
cin>>a[i],yc[a[i]]=i;
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++){
if(fl[i]) continue;
int mn=2e9,nm=1,nw=i;
while(!fl[nw]){
mn=min(mn,w[a[nw]]),nm++;
fl[nw]=1,nw=yc[b[nw]];
}ans+=min((nm-3)*mn,nm*minn+mn);
}cout<<ans;
return 0;
}