1. 程式人生 > >【HDU 1394】Minimum Inversion Number

【HDU 1394】Minimum Inversion Number

題意:輸入一個初始序列,然後每次操作都把序列的第一個數放到最後一個位置,構成一個新的序列,問其中某一個序列的最小逆序數是多少。

思路:首先,普及一下逆序與逆序數的概念,簡單地說就是如果前面的數比後面的數大,就稱為一個逆序。一個排列中逆序的總數稱為這個排列的逆序數。

然後這道題有一個好處就是這n個數是由0~n-1組成的,那麼,這意味著什麼呢?仔細觀察後,我們不難發現

假設0~n-1中的一個數x放到了最後一個位置,那麼這個序列的逆序數就是n-1-x,這是為什麼呢,下面我們接著看

因為在這個序列中,比x小的數有x個(始終記住這n個數是由0~n-1組成的),比x大的數有n-1-x個,那麼,將x放到最後一個位置,也就是說,這個序列中的前n-1個數(去掉最後一個數)中有x個比它小的數,有n-1-x個比它大的數,所以這個序列的逆序數就是n-1-x。

我們假設初始序列的逆序數是ans,那麼把序列中的x放到最後一個位置之後,逆序數就變成了ans - x +(n-1-x),減x是因為原本x是第一個數,後面有x個比它小的數,現在把它放到了最後一個位置,那麼序列中前面有x個對於x來說是有序的,只有那n-1-x個比它大的數才是逆序,所以逆序數要-x。

所以問題就轉化成了求初始序列的逆序數,用線段樹的方法單點更新,區間求和

主要思想就是把每個數放到自己的葉子結點,然後看它前面有多少個比它大的數,最後累加就是序列的逆序數。

My  DaiMa:

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define lson l,mid,num<<1
#define rson mid+1,r,num<<1|1
const int maxn = 5005;
int sum[maxn<<2];
void push_up(int num)
{
    sum[num] = sum[num<<1] + sum[num<<1|1];
}
/*建樹*/
void TreeBuild(int l,int r,int num)
{
    sum[num] = 0;
    if(l == r) return;
    int mid = (l+r) >> 1;
    TreeBuild(lson);
    TreeBuild(rson);
    push_up(num);
}
/*每插入一個數,更新*/
void update(int x,int l,int r,int num)
{
    if(l == r)
    {
        sum[num] ++;
        return;
    }
    int mid = (l+r) >> 1;
    if(x > mid) update(x,rson);
    else update(x,lson);
    push_up(num);
}
/*查詢,判斷前面有多少個比它大的數*/
int query(int x,int y,int l,int r,int num)
{
    if(x <= l && y >= r) return sum[num];
    int ans = 0;
    int mid = (l+r) >> 1;
    if(x <= mid) ans += query(x,y,lson);
    if(y > mid) ans +=query(x,y,rson);
    return ans;
}
int main()
{
    int n,a[5005];
    while(cin >> n)
    {
        TreeBuild(0,n-1,1);
        int ans = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%d",&a[i]);
            ans += query(a[i],n-1,0,n-1,1);//先查詢
            update(a[i],0,n-1,1);//後更新
        }
        int minn = ans;
        for(int i = 0; i < n; i++)
        {
            ans = ans - a[i] + (n - 1 - a[i]);
            minn = min(minn,ans);
        }
        cout << minn << endl;
    }
}