博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

[51nod1125]交换机器的最小代价

设每个数最终的位置是$p_i$, 每个数当前的位置是$i$, 由于数是独一无二的, 所以pi - i是一一映射的关系

然后我们让$i -> p_i$, 建立一个图

那么, 考虑一个环, 我们可以让最小的值沿着来边走一$n-1$步($n$是环的大小), 亦或是让最小值和全局最小值交换一下, 让全局最小值来代替他走一圈, 再把全局最小值交换回去

(感觉显然是对的)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define pb push_back
#define ln '\n'
const int N = 2e5+5;
const int mod = 998244353;
inline void inc(int &a, int b){
    a+=b;
    if(a>=mod) a-=mod;
}
inline void dec(int &a, int b){
    a-=b;
    if(a<0) a+=mod;
}
int n, p[N], f[N], mn[N], siz[N];
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
ll sum[N];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n;
    vector<int> b;
    for(int i=1; i<=n; i++) cin >> p[i], b.pb(p[i]);
    sort(b.begin(), b.end());
    for(int i=1; i<=n; i++)
    	p[i] = lower_bound(b.begin(), b.end(), p[i])-b.begin() + 1;
    for(int i=1; i<=n; i++)
    	f[i] = i, sum[i] = mn[i] = b[p[i]-1], siz[i] = 1;
    for(int i=1; i<=n; i++){
    	int fx = find(i), fy = find(p[i]);
    	if(fx != fy){
    		f[fy] = fx; 
    		sum[fx] += sum[fy]; 
    		mn[fx] = min(mn[fx], mn[fy]); 
    		siz[fx] += siz[fy];
    	}
    }
    ll ans = 0;
    for(int i=1; i<=n; i++)
    	if(f[i] == i){
    		ll tmp1 = sum[i] - mn[i] + 1ll * mn[i] * (siz[i]-1);
    		ll tmp2 = sum[i] - mn[i] + 1ll * b[0] * (siz[i]-1) + (b[0]+mn[i])*2;
    		//把1跟最小值换一下, 然后让1走一圈, 然后换回来
    		ans = ans + min(tmp1, tmp2);
    	}
    cout << ans << ln;
}

  

posted @ 2022-07-17 19:35  gllonkxc  阅读(36)  评论(0编辑  收藏  举报