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

题意:

        有一个n个整数的排列,这n个整数就是0,1,2,3...n-1n个数(但不一定按这个顺序给出)。现在先计算一下初始排列的逆序数,然后把第一个元素a1放到an后面去,形成新排列a2 a3 a4...an a1,然后再求这个排列的逆序数。继续执行类似操作(一共要执行n-1)直到产生排列an a1 a2...an-1为止。计算上述所有排列的逆序数,输出最小逆序数。

题解:

        对于原始数列,易用树状数组计算出序列的逆序数。设序列中比a1小的个数为x,比a1大的个数为y,所以将a1移动至最后形成的序列相比较原来的数列,增加了y,减少了x。所以每次移动都是原来的加上y-x即可。有y+x+1=n。可得y-x = n+1-2*a1.


#include<bits/stdc++.h>

using namespace std;

const int maxn = 5000+10;
int c[maxn];

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

int sum(int x)
{
    int res=0;
    while(x>0)
    {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

void add(int x,int v)
{
    while(x<maxn)
    {
        c[x]+=v;
        x += lowbit(x);
    }
}
int a[maxn];
int main()
{
    int n;
    while(cin>>n)
    {
        int cnt=0;
        memset(c,0,sizeof c);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",a+i);
            a[i]++;
            cnt+=i-1-sum(a[i]);
            add(a[i],1);
        }

        int ans=cnt;///排列的逆序数
        for(int i=1;i<n;i++)
        {
            cnt += n+1-2*a[i]; ///每次移动  
            ans = min(ans,cnt);
        }
        cout<<ans<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/sgh666666/article/details/80439847