P6193 [USACO07FEB] Cow Sorting G 题解

题目链接

猜结论+推式子题

猜结论

先想下这道题的弱化版,不用考虑 \(a_i\),那么就变成了单单求最少交换次数。然后就回忆起了AT_abc436_e,有个很有意思的东西,叫做置换环,那么答案就是 \(n-cnt\),其中 \(cnt\) 表示环的个数。然后置换环又有一个性质:环内任意两点交换都不会使得答案偏大,因为每一次交换,都会把环给拆成两个更小的环,因此不影响。

那么,我们不妨猜测每一次选择最小的点,让其当尼格,进行交换。但是很容易想到,这样子存在问题,如果环上的点都非常大,那么就还不如选择全局最少。

推式子

先规定,\(min_1\) 表示环上最小,\(min_2\) 表示全局最小。

首先考虑在环上,那么答案就是 \((siz-2)*min_1+sum\),因为环上最小的点要和其他点交换 \(siz-1\) 次,但是其自身又被包含在了 \(sum\) 中,因此是 \(siz-2\)

然后考虑不在环上,那么答案可拆成:交换 \(min_1\)\(min_2\),然后让 \(min_2\) 代替 \(min_1\) 成为尼格。则答案为 \((siz+1)×min_2+sum+min_1)\)

答案取个 \(min\),完结撒花!

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 1e5 + 10;
int a[N];
int n;
int b[N],id[N];
bool vis[N];
int main()
{
	IOS;
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> a[i];
		b[i] = a[i];
	}
	sort(b+1,b+1+n);
	for(int i=1;i<=n;i++)
		id[i] = lower_bound(b+1,b+1+n,a[i]) - b;
	LL ans = 0;
	for(int i=1;i<=n;i++){
		if(vis[i]) continue;
		LL sum = 0;
		int minn = N;
		int x = i;
		int siz = 0;
		while(vis[x]==0){
			siz ++ ;
			vis[x] = 1;
			sum += a[x];
			minn = min(minn,a[x]);
			x = id[x];
		}
		ans += min(sum + 1ll * minn * (siz-2),sum + 1ll * b[1] * (siz + 1) + minn);
	}
	cout << ans;
	return 0;
}
posted @ 2026-01-12 21:59  WinterXorSnow  阅读(1)  评论(0)    收藏  举报