hdu 1394 Minimum Inversion Number (裸树状数组 求逆序数 && 归并排序求逆序数)

题目链接

题意:

给一个n个数的序列a1, a2, ..., an ,这些数的范围是0~n-1, 可以把前面m个数移动到后面去,形成新序列:
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
求这些序列中,逆序数最少的是多少?

 

树状数组:

分析:c数组里的值代表个数,下标代表等于哪个值,是按照顺序排的,所以sum(n)-sum(a[i]),就能减出来比a[i]大的数值了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <map>
 7 #include <algorithm>
 8 #define LL __int64
 9 const int maxn = 5000+10;
10 using namespace std;
11 int c[maxn], a[maxn], n;
12 
13 int lowbit(int x)
14 {
15     return x&(-x);
16 }
17 void add(int x,int d)
18 {
19     while(x <= n)
20     {
21         c[x] += d;
22         x +=lowbit(x);
23     }
24 }
25 LL sum(int x)
26 {
27     LL ret = 0;
28     while(x > 0)
29     {
30         ret += c[x];
31         x -= lowbit(x);
32     }
33     return ret;
34 }
35 
36 int main()
37 {
38     int i, ans, tmp;
39     while(~scanf("%d", &n))
40     {
41         ans = 0;
42         memset(c, 0, sizeof(c)); //不要忘了清0
43         for(i = 1; i <= n; i++)
44         {
45             scanf("%d", &a[i]);
46             a[i] ++;  //因为是从0到n-1的
47             ans += sum(n)-sum(a[i]);  //貌似a[i]太大的话就不行了吧
48             add(a[i], 1);         //c数组里的值代表个数,下标代表等于哪个值
49         }
50         tmp = ans;
51         for(i = 1; i <= n; i++)
52         {
53             tmp += n-a[i]-(a[i]-1); //是一个公式,我没想明白为什么
54             ans = min(ans, tmp);
55         }
56         printf("%d\n", ans);
57     }
58     return 0;
59 }

 

归并排序的做法:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <algorithm>
 6 #define LL __int64
 7 const int maxn = 5000+10;
 8 using namespace std;
 9 int n;
10 int sum, b[maxn], a[maxn], a2[maxn];
11 
12 void merge_sort(int *A, int x, int y, int *T)
13 {
14     if(y-x>1)
15     {
16         int m=x+(y-x)/2;
17         int p=x, q=m, i=x;
18         merge_sort(A,x,m,T);
19         merge_sort(A,m,y,T);
20         while(p<m || q<y)
21         {
22             if(q>=y ||(p<m && A[p] <= A[q]))
23                 T[i++] = A[p++];
24             else
25             {
26                 T[i++] = A[q++];
27                 sum+=m-p;
28             }
29 
30         }
31         for(i=x; i<y; i++)
32             A[i] = T[i];
33     }
34 };
35 
36 int main()
37 {
38     int i;
39     int tmp;
40     while(~scanf("%d", &n))
41     {
42         sum = 0;
43         memset(b, 0, sizeof(b));
44         for(i = 0; i < n; i++) //注意这是从0开始的,因为归并排序的原因
45         {
46             scanf("%d", &a[i]);
47             a2[i] = a[i];
48         }
49         merge_sort(a, 0, n, b);
50         tmp = sum;
51         for(i = 0; i < n; i++)
52         {
53             tmp += n-1-a2[i]-a2[i]; //一定要注意这个是a2[]; 因为之前的a[]的顺序已经改变了。还要注意这个公式
54             sum = min(sum, tmp);        //和上一个树状数组的不同是上一个a[]++了。
55         }
56         printf("%d\n", sum);
57     }
58     return 0;
59 }

 

posted @ 2014-08-16 20:20  水门  阅读(166)  评论(0编辑  收藏  举报