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

HDU1394 Minimum Inversion Number 线段树+数学

时间:2015-02-23 23:44:23      阅读:400      评论:0      收藏:0      [点我收藏+]

标签:

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

解题思路

这题折腾了一晚上才AC 还是太粗心了。

因为数据小,貌似暴力也是可以过的。用线段树当然更好。
解题分为两步
①先不考虑移动,用O(nlogn)把初始的逆序对个数算出来(假设是sum)

②用数学公式用O(1)递推sum 找到最小情况的sum

先看第一步,用线段树。每读入一个数我们只考虑在它之前已经读入的数。便于统计我们将所有的s[i]++成为1-n的正整数。再看当前读入的这个数和n之间的这一段距离已经存在了几个数。他们就是当前这个数的”前瞻逆序对”

第二步。假设当前逆序对是sum个。现在考虑第一个数 假设是k 将它放到队伍的最后面。我们知道在第2到第n个数中有k-1个是小于k的,n-k个是大于k的。所以这么一移动,自然逆序对数量就少了k-1个,多了n-k个。这样不断循环,不断更新最小值。

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 5010;
int n;
int s[maxn];
int ans[maxn];
int segTree[maxn<<2];
void update(int node,int k,int l,int r)
{
    if(l <= k && k <= r) segTree[node] ++;
    if(l == r) return;
    if(r < k || l > k) return;
    update(node<<1,k,l,(l+r)/2);
    update((node<<1)+1,k,(l+r)/2+1,r);
}
int query(int a,int b,int node,int l,int r)
{
    if(l > b || r < a) return 0;
    if(a <= l && r <= b) return segTree[node];
    return query(a,b,node<<1,l,(l+r)/2)+query(a,b,(node<<1)+1,(l+r)/2+1,r);
}
int main()
{
    while(scanf("%d",&n) != EOF) {
        memset(s,0,sizeof(s));
        memset(ans,0,sizeof(ans));
        memset(segTree,0,sizeof(segTree));
        for(int i = 1 ; i <= n ; i ++) {
            scanf("%d",&s[i]);
            s[i] ++;
            ans[i] = query(s[i],n,1,1,n);
            update(1,s[i],1,n);
        }
        int sum = 0;
        for(int i = 1 ; i <= n ; i ++) sum += ans[i];
        int mi = sum;
        for(int i = 1 ; i < n ; i ++) {
            sum = sum+1+n-2*s[i];
            if(sum < mi) mi = sum;
        }
        printf("%d\n",mi);
    }
    return 0;
}

HDU1394 Minimum Inversion Number 线段树+数学

标签:

原文地址:http://blog.csdn.net/area_52/article/details/43919117

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