HDU 1394 - Minimum Inversion Number(逆序數-線段樹 | 樹狀數組)

- HDU 1394 -

Minimum Inversion Number

Time Limit: 2000/1000 MS (Java/Others) | Memory Limit: 65536/32768 K (Java/Others)

題意:

給定數字序列 a1,a2,…,an 的反轉數是滿足 i < j 和 ai > aj 的對(ai,aj)的數量。
對於給定的數字序列 a1,a2,…,an,把該序列最前面的數移到序列最後面,就會得到一個新的序列,經過 n-1 次該操作後,我們就有一共 n 個序列,找出這些序列中的最小反轉數。
輸入:有多組測試數據,每組第一行給定一個整數 n ,接下來一行包含從0到n-1的n個整數的排列。

數據範圍:

n <= 5000

解題思路:

線段樹 or 樹狀數組

這題本質上是求序列中的逆序對數,並求出所有序列中逆序對數最少的那個。之前求逆序數都是用的樹狀數組,這還是第一次用線段樹來求。

代碼:

① 線段樹:
Exe.Time : 46MS | Exe.Memory : 1776K

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define zero 1e-7
#define lowbit(x) x&(-x)

typedef long long ll;
const int N=1e5+5;
const int maxn=5e3+5;

int a[maxn], sum[maxn<<2];

void build(int l, int r, int p) {//建一棵空樹
    sum[p]=0;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(l, mid, p<<1);
    build(mid+1, r, (p<<1)|1);
}

void update(int l, int r, int p, int c) {
    if(l==r) {
        sum[p]++;
        return ;
    }
    int mid=(l+r)>>1;
    if(c<=mid) update(l, mid, p<<1, c);
    else update(mid+1, r, (p<<1)|1, c);
    sum[p]=sum[p<<1]+sum[(p<<1)|1];
}

int query(int l, int r, int p, int s, int t) {
    if(s<=l && r<=t) return sum[p];
    int mid=(l+r)>>1;
    int ans=0;
    if(s<=mid) ans+=query(l, mid, p<<1, s, t);
    if(t>mid) ans+=query(mid+1, r, (p<<1)|1, s, t);
    return ans;
    //printf("a[i]=%d, ans=%d\n", s, ans);
}

int main() {
    int n;
    while(scanf("%d", &n)!=EOF) {
        build(0, n-1, 1);
        int ans=0;
        for(int i=0; i<n; i++) {
            scanf("%d", &a[i]);
            ans+=query(0, n-1, 1, a[i], n);//區間,節點,查詢區間
            update(0, n-1, 1, a[i]);//區間,節點,待更新的葉節點
        }
        int res=ans;
        for(int i=0; i<n; i++) {
            ans+=n-a[i]-a[i]-1;//減去比a[i]小的(a[i]個),加上比a[i]大的(n-a[i]-1個)
            res=min(res, ans);
            //printf("%dans=%3d\n", i+1, ans);
        }
        printf("%d\n", res);
    }
    return 0;
}

② 樹狀數組:
Exe.Time : 46MS | Exe.Memory : 1764K

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
#define zero 1e-7
#define lowbit(x) x&(-x)

typedef long long ll;
const int N=1e5+5;
const int maxn=5e3+5;

int a[maxn], sum[maxn], n;

void add(int x) {
    while(x<=n) {
        sum[x]++;
        x+=lowbit(x);
    }
    return ;
}

int query(int x) {
    int ans=0;
    while(x) {
        ans+=sum[x];
        x-=lowbit(x);
    }
    return ans;
}

int main() {
    while(scanf("%d", &n)!=EOF) {
        memset(sum, 0, sizeof(sum));
        for(int i=1; i<=n; i++) {
            scanf("%d", &a[i]);
            a[i]++;
        }
        int ans=0;
        for(int i=n; i; i--) {
            ans+=query(a[i]);
            add(a[i]);
        }
        int res=ans;
        for(int i=1; i<n; i++) {
            int temp=query(a[i]-1);
            ans-=temp;
            ans+=n-1-temp;
            res=min(res, ans);
        }
        printf("%d\n", res);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章