hdu 1394 Minimum Inversion Number

点击打开hdu 1394

思路: 线段树+单点更新

分析:

1 题目要求的是n个数的n个序列中找到的最小逆序数对

2 首先我们都知道所谓的逆序数对就是给一个序列,如果前面的数比当前的数大,那么这两个数就是逆序数对。比如4 1 3 2中逆序数有 4 1, 4 3, 4 2, 3 2

3 那么我们可以很快的利用线段树求出起始数组的逆序数对,那么我们接下来考虑把第一个数换到最后一个位置的情况

   假设现在起始的序列的逆序数对有sum,那么第一个数num[1]换到最后一个位置的后果就是使得所有比num[i]小的数度不能和num[i]构成逆序数了,那么直接减少的个数就是n-1-num[i],但是那么比num[i]大的数可以和num[i]构成逆序数,因此增加了n-num[i]个。因此换完之后的序列的逆序数对为sum-(n-1-num[i])+n-num[i];

4 因此我们只要去做n次的比较,求出的最小值即为ans


代码:

/************************************************
 * By: chenguolin                               * 
 * Date: 2013-09-01                             *
 * Address: http://blog.csdn.net/chenguolinblog *
 ************************************************/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

#define Lson(x) (x<<1)
#define Rson(x) (Lson(x)|1)
#define Mid(x,y) ((x+y)>>1)
#define Sum(x,y) (x+y)

typedef long long int64;
const int MAXN = 5010;

int n;
int num[MAXN];
struct Node{
    int left;
    int right;
    int64 sum;
};
Node node[4*MAXN];

void push_up(int pos){
    node[pos].sum = Sum(node[Lson(pos)].sum , node[Rson(pos)].sum);
}

void init(int left , int right , int pos){
    node[pos].left = left;
    node[pos].right = right;
    if(node[pos].left == node[pos].right){
       node[pos].sum = 0;
       return;
    }
    int mid = Mid(left , right);
    init(left , mid , Lson(pos));
    init(mid+1 , right , Rson(pos));
    push_up(pos);
}

void update(int index , int val , int pos){
    if(node[pos].left == node[pos].right){
        node[pos].sum += val;
        return;
    }
    int mid = Mid(node[pos].left , node[pos].right);
    if(index <= mid)
        update(index , val , Lson(pos));
    else
        update(index , val , Rson(pos));
    push_up(pos);
}

int64 query(int left , int right , int pos){
    if(node[pos].left == left && node[pos].right == right)
        return node[pos].sum;
    int mid = Mid(node[pos].left , node[pos].right);
    if(right <= mid)
        return query(left , right , Lson(pos));
    else if(left > mid)
        return query(left , right , Rson(pos));
    else
        return query(left , mid , Lson(pos))+query(mid+1 , right , Rson(pos));
}

int64 input(){
    if(n == 0) return 0;
    init(1 , n , 1);
    int64 ans = 0;
    int64 sum = 0;
    for(int i = 1 ; i <= n ; i++){
        scanf("%d" , &num[i]);
        num[i]++;
        if(num[i] < n)
           sum += query(num[i]+1 , n , 1);
        update(num[i] , 1 , 1);
    }
    ans = sum;
    for(int i = 1 ; i <= n ; i++){
        sum = sum-(num[i]-1)+(n-num[i]);
        ans = min(ans , sum);
    }
    return ans;
}

int main(){
    while(scanf("%d" , &n) != EOF)
         printf("%lld\n" , input());
    return 0;
}



你可能感兴趣的:(hdu 1394 Minimum Inversion Number)