群论学习笔记

本文有着大量的感性理解。


一、置换

实际上可以理解为对集合的每个元素一个新的标号,满足这个标号集合与原集合一一对应。

如集合 \(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;
} 
posted @ 2024-12-08 19:59  长安一片月_22  阅读(1)  评论(0编辑  收藏  举报