码迷,mamicode.com
首页 > 其他好文 > 详细

Minimum Inversion Number

时间:2015-03-11 16:58:40      阅读:143      评论:0      收藏:0      [点我收藏+]

标签:

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
 大意:求最小逆序数,分为两个步骤,第一个步骤求出原来序列的逆序数,第二个步骤循环n-1次求每个状态的逆序数,最后输出最小值。用暴力解可能会超时,好像可以用线段树和逆序数组,不过现在只会一点点的线段树,用一个线段数,在每个值存储左右端点的值以及逆序数的个数,用两个query和update函数,query函数用来输出从left到right的数的逆序数,一个数的逆序数存在于本身到最大值,即a[n]到n-1(因为是从0到n-1),如果n-1小于等于mid的话,说明是在他的左儿子中所有的值;如果left大于mid的话,说明是右儿子的所有的值;否则就是左右儿子中都有,而update函数则是输入一个数就更新拥有该数的节点,因为build建起来的数从左到右是1到n-1的,所以用mid来进行左右儿子的判断,更新。
技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX = 5555;
struct segtree{
    int left;
    int right;
    int val;
}tt[MAX << 2];
void build(int n, int left ,int right)
{
    tt[n].left = left;
    tt[n].right = right;
    tt[n].val = 0;
    if(left == right) return ;
    int mid = (tt[n].left + tt[n].right) >> 1;
    build(n << 1, left, mid);
    build(n << 1|1, mid + 1, right);
}

int query(int n, int left ,int right)
{
    if(tt[n].left == left && tt[n].right == right)
        return tt[n].val;//根节点
   int mid = (tt[n].left + tt[n].right) >> 1;
   if(right <= mid)
   return query(n << 1, left ,right);
  else if(left > mid)
    return query(n << 1|1, left, right);
  else return query(n << 1,left, mid) + query(n << 1|1, mid + 1,right);
}
void update(int n, int idx)
{
    tt[idx].val++;
    if(tt[idx].left == tt[idx].right) return ;
    int mid = (tt[idx].left + tt[idx].right) >> 1;
    if( n <= mid )
        update(n, idx << 1);
    else update(n , idx << 1|1);
}
int main()
{
    int n,a[MAX], ans ;
    while(~scanf("%d",&n)){
        build(1, 0, n - 1 );
       int sum = 0;
            for(int i = 0; i < n ; i++){
                scanf("%d", &a[i]);
                sum += query(1,a[i],n - 1);
                update(a[i],1);
            }
            ans = sum;
            for(int i = 0; i < n ; i++){
                sum = sum - a[i] + (n - 1 - a[i]);
              ans = min(ans, sum);
            }
    printf("%d\n",ans);
    }
    return 0;
}
View Code

 

Minimum Inversion Number

标签:

原文地址:http://www.cnblogs.com/zero-begin/p/4330199.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!