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;
}

浙公网安备 33010602011771号