[HDOJ1394]Minimum Inversion Number(线段树,逆序数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394

题意:一个数的逆序数为inv,然后求这个数列的第一个数后变为最后一个数,过程中逆序数最小的时候的逆序数。

用线段树,先建立一棵空树,之后向树内插点。在插入之前进行一次统计,求出比这个数大的个数,累计相加。得出当前逆序数。也可用归并排序、树状数组之类的方法。

之后移动每次的第一个数,可以用二分搜两遍,求出多少个数比它大,多少个数比它小。用当前逆序数加上比它大的数的个数,减去比它小的个数即可求得当前逆序数。

也可以得到规律:第i个数变成第n-1数的时候,要减去后面比它小的数(tmp[i]个),要加上后面比它大的数(n-tmp[i]+1个)。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <iomanip>
 4 #include <cstring>
 5 #include <climits>
 6 #include <complex>
 7 #include <fstream>
 8 #include <cassert>
 9 #include <cstdio>
10 #include <cstdlib>
11 #include <bitset>
12 #include <vector>
13 #include <deque>
14 #include <queue>
15 #include <stack>
16 #include <ctime>
17 #include <set>
18 #include <map>
19 #include <cmath>
20 
21 using namespace std;
22 
23 #define lson l, m, rt << 1
24 #define rson m + 1, r, rt << 1 | 1
25 const int maxn = 6666;
26 int num[maxn<<2];
27 int tmp[maxn];
28 
29 void pushUP(int rt) {
30     num[rt] = num[rt<<1] + num[rt<<1|1];
31 }
32 
33 void build(int l, int r, int rt) {
34     num[rt] = 0;
35     if(l == r) {
36         return;
37     }
38     int m = (l + r) >> 1;
39     build(lson);
40     build(rson);
41 }
42 
43 void update(int p, int l, int r, int rt) {
44     if(l == r) {
45         num[rt]++;
46         return;
47     }
48     int m = (l + r) >> 1;
49     if(p <= m) {
50         update(p, lson);
51     }
52     else {
53         update(p, rson);
54     }
55     pushUP(rt);
56 }
57 
58 int query(int L, int R, int l, int r, int rt) {
59     if(L <= l && r <= R) {
60         return num[rt];
61     }
62     int m = (l + r) >> 1;
63     int cur = 0;
64     if(L <= m) {
65         cur += query(L, R, lson);
66     }
67     if(R > m) {
68         cur += query(L, R, rson);
69     }
70     return cur;
71 }
72 
73 int main() {
74     // freopen("in", "r", stdin);
75     int n;
76     while(~scanf("%d", &n)) {
77         build(0, n-1, 1);
78         int inv = 0;
79         for(int i = 0; i < n; i++) {
80             scanf("%d", &tmp[i]);
81             inv += query(tmp[i], n-1, 0, n-1, 1);
82             update(tmp[i], 0, n-1, 1);
83         }
84         int ans = 0;
85         for(int i = 0; i < n; i++) {
86             inv = inv - tmp[i] + n - tmp[i] - 1;
87             ans = min(ans, inv);
88         }
89         printf("%d\n", ans);
90     }
91     return 0;
92 }

 

你可能感兴趣的:([HDOJ1394]Minimum Inversion Number(线段树,逆序数))