Cow Sortingnode
接觸到置換羣的概念,對於一個(1~n)的一個排列a1, a2, a3...anios
1 2 3 4 5 ... nspa
a1 a2 a3 a4 a5...ancode
看做是一個置換,那麼將其寫爲若干個不相交的循環的乘積形式(A1, A2, ... Ap1)(B1, B2, ... Bp2)... ...,例如blog
1 2 3 4 5 6get
3 5 6 4 2 1string
能夠寫爲(1 3 6)(2 5)(4)的形式,這裏能夠當作有3個循環(能夠理解爲上面的1 3 6這個集合,對應在下面也是 1 3 6)it
那麼對應在每個循環中,能夠經過最多Ki - 1此交換使得這個循環有序,這裏的Ki表示第i個循環的集合的大小。也就是說每交換一次能夠使得一個元素回到本身的位置,因爲交換的代價是這兩個元素值的和,那麼根據貪心的思想,每次選擇用這個循環中的最小值將其餘元素交換到對應的位置上去。那麼總代價就是io
SUMi + (Ki - 2) * Miclass
這裏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 }