Minimum Inversion Number BNUOJ 5594

题意:求Inversion后的最小逆序数(n<=5000)

思路:一、暴力。(以n的范围来看貌似可以,未尝试。)

   二、树状数组。//就跑的时间来看还是树状数组(46ms)比较快,不过也许是我的线段树(78ms)写疵了。

    1.用树状数组求逆序对数。

     用样例1 3 6 9 0 8 5 7 4 2说明。sum=0;a[1]=1;sum+=c[n]-c[3]=0;a[3]=1;sum+=c[n]-c[6]=0;a[6]=1;sum+=c[n]-c[9]=0;a[9]=1;sum+=c[n]-c[0]=4;a[0]=1;sum+=c[n]-c[8]=5;a[8]=1;sum+=c[n]-c[5]=8;a[5]=1;sum+=c[n]-c[7]=10;a[7]=1;sum+=c[n]-c[4]=15;a[4]=1;sum+=c[n]-c[2]=22;a[2]=1;

     大致思路是这样,在代码里我做了离散化。

    2.每次将队首的一个数移至队尾计算逆序数。由于队列中的数为0-n-1。那么,对于队首的x,比它大的有n-x-1个,比它小的有x个。每移动一次,逆序数变化量为(n-x-1)-x.比较更新即可。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 #define MAX 5010
 5 
 6 using namespace std;
 7 
 8 struct node{
 9     int pos,val;
10 }a[MAX];
11 
12 int c[MAX];
13 int x[MAX];
14 int n;
15 int lowbit(int i){
16     return(i&(-i));
17 }
18 int getsum(int i) {
19     int sum =0;
20     while (i>0){
21         sum += c[i];
22         i -= lowbit(i);
23     }
24     return sum;
25 }
26 void update(int i, int val){
27     while (i<=n){
28         c[i] += val;
29         i += lowbit(i);
30     }
31 }
32 bool cmp(node a,node b){
33     return a.val>b.val;
34 }
35 
36 int main(){
37     int sum=0;
38     int i;
39     while(scanf("%d",&n)!=EOF){
40         sum = 0;
41         memset(c,0,sizeof(c));
42         for(i=1;i<=n;i++){
43             scanf("%d",&a[i].val);
44             x[i]=a[i].val;
45             a[i].pos = i;
46         }
47         sort(a+1,a+n+1,cmp);
48         for(i=1;i<=n;i++){
49             sum += getsum(a[i].pos);
50             update(a[i].pos,1);
51         }
52         //printf("%d\n",sum);
53         int ret=sum;
54         for(int i=1;i<=n;++i){
55             sum+=n-x[i]-x[i]-1;
56             if(sum<ret)ret=sum;
57         }
58         printf("%d\n",ret);
59     }
60     return 0;
61 }

 

   三、线段树。(线段树的作法与树状数组类似。)

    更新和维护方法与树状数组一致,只是调用函数和写法的差别。

 1 #include <cstdio>
 2 
 3 #define lson l , m , rt << 1
 4 #define rson m + 1 , r , rt << 1 | 1
 5 const int maxn = 5010;
 6 int sum[maxn<<2];
 7 int x[maxn];
 8 void PushUP(int rt) {
 9     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
10 }
11 void build(int l,int r,int rt) {
12     if (l == r) {
13         sum[rt]=0;
14         return ;
15     }
16     int m = (l + r) >> 1;
17     build(lson);
18     build(rson);
19     PushUP(rt);
20 }
21 void update(int p,int add,int l,int r,int rt) {
22     if (l == r) {
23         sum[rt] += add;
24         return ;
25     }
26     int m = (l + r) >> 1;
27     if (p <= m) update(p , add , lson);
28     else update(p , add , rson);
29     PushUP(rt);
30 }
31 int query(int L,int R,int l,int r,int rt) {
32     if (L <= l && r <= R) {
33         return sum[rt];
34     }
35     int m = (l + r) >> 1;
36     int ret = 0;
37     if (L <= m) ret += query(L , R , lson);
38     if (R > m) ret += query(L , R , rson);
39     return ret;
40 }
41 int main() {
42     int n,sum;
43     while(scanf("%d",&n)!=EOF){
44         build(1,n,1);
45         sum=0;
46         for(int i=1;i<=n;++i){
47             scanf("%d",&x[i]);
48             sum+=query(x[i]+1,n,1,n,1);
49             update(x[i]+1,1,1,n,1);
50         }
51         int ret=sum;
52         for(int i=1;i<=n;++i){
53             sum+=n-x[i]-x[i]-1;
54             if(sum<ret)ret=sum;
55         }
56         printf("%d\n",ret);
57         }
58     return 0;
59 }

 

                                                             Q

posted on 2012-07-31 01:42  miao11621  阅读(159)  评论(0编辑  收藏  举报

导航