HDU 1394 (逆序数) Minimum Inversion Number

原来求逆序数还可以用线段树,涨姿势了。

首先求出原始序列的逆序数,然后递推每一个序列的逆序数。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 20000 + 10;
 7 
 8 int n, p, qL, qR;
 9 int sum[maxn], a[5000 + 10];
10 
11 void update(int o, int L, int R)
12 {
13     if(L == R) { sum[o]++; return; }
14     int M = (L + R) / 2;
15     if(p <= M) update(o*2, L, M);
16     else update(o*2+1, M+1, R);
17     sum[o] = sum[o*2] + sum[o*2+1];
18 }
19 
20 int query(int o, int L, int R)
21 {
22     if(qL <= L && qR >= R) return sum[o];
23     int ans = 0;
24     int M = (L + R) / 2;
25     if(qL <= M) ans += query(o*2, L, M);
26     if(qR > M) ans += query(o*2+1, M+1, R);
27     return ans;
28 }
29 
30 int main()
31 {
32     //freopen("in.txt", "r", stdin);
33 
34     while(scanf("%d", &n) == 1)
35     {
36         memset(sum, 0, sizeof(sum));
37 
38         for(int i = 0; i < n; i++) scanf("%d", &a[i]);
39         int inv = 0;
40         for(int i = 0; i < n; i++)
41         {
42             p = a[i];
43             qL = a[i]; qR = n - 1;
44             inv += query(1, 0, n - 1);
45             update(1, 0, n - 1);
46         }
47         int ans = inv;
48         for(int i = 0; i < n; i++)
49         {
50             inv = inv + n - a[i]*2 - 1;
51             ans = min(ans, inv);
52         }
53         printf("%d
", ans);
54     }
55 
56     return 0;
57 }
线段树

既然要求逆序数了,干脆树状数组,归并排序也都试一试。

由于树状数组lowbit的特点,所以数组下标是从1开始的。但是树状数组要比线段树好写很多。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 5000 + 10;
 7 int n;
 8 int a[maxn], s[maxn];
 9 
10 inline int lowbit(int x) { return x&(-x); }
11 
12 int sum(int x)
13 {
14     int ans = 0;
15     while(x > 0) { ans += s[x]; x -= lowbit(x); }
16     return ans;
17 }
18 
19 void add(int x, int d)
20 {
21     while(x <= n) { s[x] += d; x += lowbit(x); }
22 }
23 
24 int main()
25 {
26     //freopen("in.txt", "r", stdin);
27 
28     while(scanf("%d", &n) == 1)
29     {
30         memset(s, 0, sizeof(s));
31         for(int i = 0; i < n; i++) { scanf("%d", &a[i]); a[i]++; }
32         int inv = 0;
33         for(int i = 0; i < n; i++)
34         {
35             inv += sum(n) - sum(a[i]);
36             add(a[i], 1);
37         }
38         int ans = inv;
39         for(int i = 0; i < n; i++)
40         {
41             inv = inv + n + 1 - a[i]*2;
42             ans = min(ans, inv);
43         }
44         printf("%d
", ans);
45     }
46 
47     return 0;
48 }
树状数组

下面是归并排序,_(:зゝ∠)_

代码不长,但是感觉还是挺容易写错的。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int maxn = 5000 + 10;
 7 int n, inv;
 8 int a[maxn], b[maxn], T[maxn];
 9 
10 void MergeSort(int x, int y)
11 {
12     if(y - x > 1)
13     {
14         int m = (x + y) / 2;
15         int p = x, q = m, i = x;
16         MergeSort(x, m); MergeSort(m, y);
17         while(p < m || q < y)
18         {
19             if(q >= y || (p < m && a[p] <= a[q])) T[i++] = a[p++];
20             else { T[i++] = a[q++]; inv += m - p; }
21         }
22         for(i = x; i < y; i++) a[i] = T[i];
23     }
24 }
25 
26 int main()
27 {
28     //freopen("in.txt", "r", stdin);
29 
30     while(scanf("%d", &n) == 1)
31     {
32         for(int i = 0; i < n; i++) { scanf("%d", &a[i]); b[i] = a[i]; }
33         inv = 0;
34         MergeSort(0, n);
35         int ans = inv;
36         for(int i = 0; i < n; i++)
37         {
38             inv = inv + n - 1 - b[i]*2;
39             ans = min(ans, inv);
40         }
41         printf("%d
", ans);
42     }
43 
44     return 0;
45 }
归并排序
原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4456563.html