HDU 1394Minimum Inversion Number 数状数组 逆序对数量和

Minimum Inversion Number

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

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

ZOJ Monthly, January 2003

Recommend

Ignatius.L   |   We have carefully selected several similar problems for you:  1166 1698 1540 1542 1255

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394


题意:求出对(ai,aj)(i<j,ai>aj)的全部数量。即求ai右边比ai小的数的个数和。每次变换a的序列,求出最小的逆序对数量和。

思路: 因为树状数组的最基本功能就是求比某点 x 小的点的个数。所以逆向存储ai。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAXN=1e6+100,INF=1e9+100;
int a[MAXN],c[MAXN],ans[MAXN];
int lowbit(int x)
{
    return x&(-x);
}
void add(int i,int val)
{
    for(i; i<=MAXN; i+=lowbit(i))
        c[i]+=val;
}
int sum(int i)
{
    int s=0;
    for(i; i>0; i-=lowbit(i))
        s+=c[i];
    return s;
}
int main()
{
    int i,j,t,n;
    while(scanf("%d",&n)!=EOF)
    {
        for(i=n; i>=1; i--)
            scanf("%d",&a[i]);
        memset(c,0,sizeof(c));
        memset(ans,0,sizeof(ans));
        int cou=0;
        for(i=1; i<=n; i++)
        {
            ans[i]=sum(a[i]+1);
            cou+=ans[i];
            add(a[i]+1,1);
        }
        int Min=cou;
        for(i=n; i>1; i--)
        {
            for(j=1; j<=n; j++)
            {
                if(j==i) continue;
                if(a[i]<a[j])
                {
                    cou++;
                    ans[j]++;
                }
            }
            cou-=ans[i];
            ans[i]=0;
            if(cou<Min) Min=cou;
        }
        cout<<Min<<endl;
    }
    return 0;
}

逆序对

时间: 2025-01-16 00:03:52

HDU 1394Minimum Inversion Number 数状数组 逆序对数量和的相关文章

HDU 1394- Minimum Inversion Number(线段树求逆序数)

Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1394 Appoint description:  System Crawler  (2015-04-13) Description The inversion number of a given number sequence a1, a

Minimum Inversion Number 数状数组

Minimum Inversion Number Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1394 Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs (ai, aj) that sat

HDU - 2838 Cow Sorting (树状数组 + 逆序对)

HDU - 2838 Cow Sorting Time Limit: 1000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description Sherlock's N (1 ≤ N ≤ 100,000) cows are lined up to be milked in the evening. Each cow has a unique "grumpiness" lev

HDU 1394 Minimum Inversion Number 树状数组&amp;&amp;线段树

题目给了你一串序列,然后每次 把最后一个数提到最前面来,直到原来的第一个数到了最后一个,每次操作都会产生一个新的序列,这个序列具有一个逆序数的值,问最小的你逆序数的值为多少 逆序数么 最好想到的是树状数组,敲了一把很快,注意把握把最后一个数提上来对逆序数的影响即可, #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring> #i

HDU 1394Minimum Inversion Number(线段树)

题目大意是说给你一个数组(N个),没戏可以将其首部的k(k<N)个元素移动至尾部,这样总共会形成N个序列 现在要求这n个序列中逆序对数最少的那一个序列有多少个逆序对 最初的确是没太多思路,就算知道线段书可以球某一个序列的逆序对数,但是这里要求n次,就没有太多把握了 而最后的方法其实的确是只用求一次的,由于给出的n个数字是0-n-1的一个排列,所以考虑吧a[0]放到最后一个位置时,那以它作为起点的逆序对数相应的会减少a[0]个(这是因为塔处在地一个位置,所有比它晓得数都会在其后方), 然后考虑a[

hdu 5193 分块 树状数组 逆序对

题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除.求每次修改后逆序对的个数. 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个. 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力.查找权值个数时,使用树状数组比较方便.内层通过树状数组维护权值. 每次更新即

HDU 1394 Minimum Inversion Number (树状数组求逆序数)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13942    Accepted Submission(s): 8514 Problem Description The inversion number of a given number sequence a1, a2, ..., a

HDU 1394 Minimum Inversion Number (树状数组求逆序对)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题目让你求一个数组,这个数组可以不断把最前面的元素移到最后,让你求其中某个数组中的逆序对最小是多少. 一开始就求原来初始数组的逆序对,树状数组求或者归并方法求(可以看<挑战程序设计>P178),然后根据最前面的元素大小递推一下每次移到最后得到的逆序数,取最小值. 1 #include <iostream> 2 #include <cstdio> 3 #include

HDU 1394 Minimum Inversion Number (树状数组)

依旧是再练习下树状数组的使用: 题目大意:   给出N个数,这些数可以把后面的删掉然后放到最前面形成新的序列 可得到的N种情况,求出这N种情况哪种的逆序数最小 解题思路:   先求出第一个序列的逆序数,然后用很巧妙的办法求下一个序列的逆序数,直到全部求出 序列 4 5 2 1 3 6 ,此序列的逆序数为7,它等到的下一个序列为 5 2 1 3 6 4 看这个新序列的产生过程,首部删除4,尾部添加4 删除4,必然会使得这个序列的逆序数减少(4-1)个,因为4前面必定有4-1个数小于4 添加4,必然