排序

题意:给出一个长为n的序列a,每次可以交换两个元素,代价为其之和,求最小总代价使得序列变为升序。

这几天怎么净看见神题了...

这题考群论思想...

考虑一个循环节,有两种把它归位的方式,一种是用循环内的最小值去挪移每个值,另一种是用全局最小值去挪移每个值

思路出来以后就ok了,真是一道神题啊qaq...

哦对要离散化

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
using namespace std;
inline int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-') op = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        (ans *= 10) += ch - '0';
        ch = getchar();
    }
    return ans * op;
}
typedef int mainint;
#define int long long 
const int inf = 0x7f7f7f7f;
const int maxn = 2e5 + 5;
int a[maxn],tp[maxn];
int to[maxn];
int minm = inf;
bool vis[maxn];
int ans;
mainint main()
{
  int n = read();
  for(int i = 1;i <= n;i++) a[i] = read(),tp[i] = a[i],minm = min(minm,a[i]);
  sort(tp + 1,tp + 1 + n);
  for(int i = 1;i <= n;i++) to[i] = lower_bound(tp + 1,tp + 1 + n,a[i]) - tp; 
  for(int i = 1;i <= n;i++)
    {
      if(vis[i]) continue;
      int m1 = inf,u = i,sz = 0,sum = 0;
      while(!vis[u] && u != to[u])
    {
      vis[u] = 1;    
      m1 = min(a[u],m1);
      sum += a[u];
      sz++;
      u = to[u];
    }
    if(!sz) continue;
      ans += min(m1 * (sz - 1) + sum - m1,minm + m1 + minm * (sz - 1) + sum  - m1 + m1 + minm);
    }
    printf("%lld",ans);
}
原文地址:https://www.cnblogs.com/LM-LBG/p/10617316.html