HDU 1394 Minimum Inversion Number (归并排序 | 线段树 | 数状数组)

Minimum Inversion Number

http://acm.hdu.edu.cn/showproblem.php?pid=1394

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5566    Accepted Submission(s): 3411

Problem Description
The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that satisfy i < j and ai > aj.
For a given sequence of numbers a1, a2, ..., an, if we move the first m >= 0 numbers to the end of the seqence, we will obtain another sequence. There are totally n such sequences as the following:
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)
You are asked to write a program to find the minimum inversion number out of the above sequences.
 
Input
The input consists of a number of test cases. Each case consists of two lines: the first line contains a positive integer n (n <= 5000); the next line contains a permutation of the n integers from 0 to n-1.
 
Output
For each case, output the minimum inversion number on a single line.
 
Sample Input
 
10
1 3 6 9 0 8 5 7 4 2
 
Sample Output
 
16
 
Author
CHEN, Gaoli
 
Source
 
 
线段树解法:
 
#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

#define L(rt) (rt<<1)
#define R(rt) (rt<<1|1)

const int N=5010;

struct Tree{
    int l,r;
    int cnt;
}tree[N<<2];

void PushUp(int rt){
    tree[rt].cnt=tree[L(rt)].cnt+tree[R(rt)].cnt;
}

void build(int L,int R,int rt){
    tree[rt].l=L;
    tree[rt].r=R;
    tree[rt].cnt=0;
    if(tree[rt].l==tree[rt].r){
        //scanf("%d",&tree[rt].x);
        return ;
    }
    int mid=(L+R)>>1;
    build(L,mid,L(rt));
    build(mid+1,R,R(rt));
}

void update(int id,int rt){
    if(tree[rt].l==tree[rt].r){
        tree[rt].cnt++;
        return ;
    }
    int mid=(tree[rt].l+tree[rt].r)>>1;
    if(id<=mid)
        update(id,L(rt));
    else if(id>=mid+1)
        update(id,R(rt));
    PushUp(rt);
}

int query(int L,int R,int rt){
    if(L==tree[rt].l && tree[rt].r==R)
        return tree[rt].cnt;
    int mid=(tree[rt].l+tree[rt].r)>>1;
    int ans=0;
    if(R<=mid)
        ans+=query(L,R,L(rt));
    else if(L>=mid+1)
        ans+=query(L,R,R(rt));
    else{
        ans+=query(L,mid,L(rt));
        ans+=query(mid+1,R,R(rt));
    }
    return ans;
}

int main(){

    //freopen("input.txt","r",stdin);

    int n,x[N];
    while(~scanf("%d",&n)){
        build(0,n-1,1);
        int ans=0;
        for(int i=0;i<n;i++){
            scanf("%d",&x[i]);
            ans+=query(x[i],n-1,1);
            update(x[i],1);
        }
        int tmp=ans;
        for(int i=0;i<n;i++){
            tmp+=n-1-x[i]-x[i];
            ans=min(ans,tmp);
        }
        printf("%d\n",ans);
    }
    return 0;
}
 
 
树状数组:
 
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

const int N=5010;

int n,arr[N],num[N];

int lowbit(int x){
    return x&(-x);
}

void update(int id,int x){
    while(id<=N){
        arr[id]+=x;
        id+=lowbit(id);
    }
}

int Sum(int id){
    int ans=0;
    while(id>0){
        ans+=arr[id];
        id-=lowbit(id);
    }
    return ans;
}

int main(){

    //freopen("input.txt","r",stdin);

    while(~scanf("%d",&n)){
        memset(arr,0,sizeof(arr));
        int ans=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
            ans+=Sum(n+1)-Sum(num[i]+1);
            update(num[i]+1,1);
        }
        int tmp=ans;
        for(int i=1;i<=n;i++){
            tmp+=n-1-num[i]-num[i];
            ans=min(ans,tmp);
        }
        printf("%d\n",ans);
    }
    return 0;
}

归并排序:

#include<cstdio>
 #include<iostream>
 using namespace std;
 const int maxn=5005;
 int num1[maxn],num2[maxn],temp[maxn];
 int sum;
 void Merge(int l,int mid,int r){
     int p=0;
     int i=l,j=mid+1;
     while(i<=mid&&j<=r){
         if(num1[i]>num1[j]){
             sum+=mid-i+1;
             temp[p++]=num1[j++];
         }
         else temp[p++]=num1[i++];
     }
     while(i<=mid)temp[p++]=num1[i++];
     while(j<=r)temp[p++]=num1[j++];
     for(i=0;i<p;i++)
         num1[l+i]=temp[i];
 }
 void MergeSort(int l,int r){
     if(l<r){
         int mid=(l+r)>>1;
         MergeSort(l,mid);
         MergeSort(mid+1,r);
         Merge(l,mid,r);
     }
 }
 int main()
 {
     int n;
     while(~scanf("%d",&n)){
         for(int i=0;i<n;i++){
             scanf("%d",&num1[i]);
             num2[i]=num1[i];
         }
         sum=0;
         MergeSort(0,n-1);
         int ans=sum;
         for(int i=0;i<n-1;i++){
             sum+=n-num2[i]-num2[i]-1;
             ans=ans<sum?ans:sum;
         }
         printf("%d\n",ans);
     }
     return 0;
 }
原文地址:https://www.cnblogs.com/jackge/p/2843300.html