接触到置换群的概念,对于一个(1~n)的一个排列a1, a2, a3...an
1 2 3 4 5 ... n
a1 a2 a3 a4 a5...an
看作是一个置换,那么将其写为若干个不相交的循环的乘积形式(A1, A2, ... Ap1)(B1, B2, ... Bp2)... ...,例如
1 2 3 4 5 6
3 5 6 4 2 1
可以写为(1 3 6)(2 5)(4)的形式,这里可以看成有3个循环(可以理解为上面的1 3 6这个集合,对应在下面也是 1 3 6)
那么对应在每一个循环中,可以通过最多Ki - 1此交换使得这个循环有序,这里的Ki表示第i个循环的集合的大小。也就是说每交换一次可以使得一个元素回到自己的位置,由于交换的代价是这两个元素值的和,那么根据贪心的思想,每次选择用这个循环中的最小值将其他元素交换到对应的位置上去。那么总代价就是
SUMi + (Ki - 2) * Mi
这里Mi表示第i个循环的最小值,SUMi表示第i个循环的和,Ki表示这个循环的元素的个数。
另外,从另一个角度出发,如果整个序列的最小值非常小,那么我们判断是不是可以先用整个序列的最小值把第i个循环的最小值Mi换出来,然后将这个集合(循环)交换到有序后,再将Mi交换回来,这样总代价就是
SUMi + (Ki + 1) * MIN + Mi
其中MIN表示整个序列的最小值。
那么,最后的答案就是 ans = SIGMA{ SUMi + min{(Ki - 2) * Mi, (Ki + 1) * MIN + Mi} }
1 #pragma comment(linker, "/STACK:1677721600") 2 #include <map> 3 #include <set> 4 #include <stack> 5 #include <queue> 6 #include <cmath> 7 #include <ctime> 8 #include <bitset> 9 #include <vector> 10 #include <cstdio> 11 #include <cctype> 12 #include <cstdarg> 13 #include <cstring> 14 #include <cstdlib> 15 #include <iostream> 16 #include <algorithm> 17 using namespace std; 18 #define INF 0x3f3f3f3f 19 #define inf (-((LL)1<<40)) 20 #define root 1, 1, n 21 #define middle ((L + R) >> 1) 22 #define lson k<<1, L, (L + R)>>1 23 #define rson k<<1|1, ((L + R)>>1) + 1, R 24 #define mem0(a) memset(a,0,sizeof(a)) 25 #define mem1(a) memset(a,-1,sizeof(a)) 26 #define mem(a, b) memset(a, b, sizeof(a)) 27 #define FIN freopen("in.txt", "r", stdin) 28 #define FOUT freopen("out.txt", "w", stdout) 29 #define rep(i, a, b) for(int i = a; i <= b; i ++) 30 #define dec(i, a, b) for(int i = a; i >= b; i --) 31 32 //typedef __int64 LL; 33 typedef long long LL; 34 typedef pair<int, int> Pair; 35 const int MAXN = 300000 + 10; 36 const int MAXM = 1100000; 37 const double eps = 1e-12; 38 LL MOD = 1000000007; 39 40 int n; 41 struct Node { 42 int a, id; 43 bool operator < (const Node &A) const { 44 return a < A.a; 45 } 46 }node[MAXN]; 47 bool vis[MAXN]; 48 49 int find_ans(int p, int &mi, int &cnt) { 50 int sum = 0; 51 mi = INF; 52 cnt = 0; 53 do { 54 sum += node[p].a; 55 vis[p] = 1; 56 cnt ++; 57 mi = min(mi, node[p].a); 58 p = node[p].id; 59 } while(!vis[p]); 60 return sum; 61 } 62 63 int main() 64 { 65 #ifndef ONLINE_JUDGE 66 FIN;// FOUT; 67 #endif 68 while(~scanf("%d", &n)) { 69 int mi = INF; 70 rep (i, 1, n) { 71 scanf("%d", &node[i].a); 72 node[i].id = i; 73 mi = min(mi, node[i].a); 74 } 75 sort(node + 1, node + n + 1); 76 mem0(vis); 77 int cur_min, cur_cnt, ans = 0; 78 rep (i, 1, n) if(!vis[i]) { 79 int sum = find_ans(i, cur_min, cur_cnt); // 找到当前循环的元素个数,最小值 80 if(cur_cnt > 1) {// mi表示所有数字中的最小值 81 ans += sum + min( (cur_cnt - 2) * cur_min, (cur_cnt + 1) * mi + cur_min ); 82 } 83 } 84 cout << ans << endl; 85 } 86 return 0; 87 }