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\n", 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\n", 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\n", ans);

42     }

43 

44     return 0;

45 }
归并排序

 

你可能感兴趣的:(version)