[HDU 1394] Minimum Inversion Number 逆序對

http://acm.hdu.edu.cn/showproblem.php?pid=1394

題意:給你一個有 n 個 小於 n 且不重複的數組成的序列,每次將序列最前面的數字移動到序列的最後面,求移動過程中序列的最小的逆序對。

思路:這題數據比較小可以先暴力出原始序列的逆序對,然後每次將最前的數移動到最後逆序對就會變成 ans = ans - num[0] + n - num[0] - 1。
這題可以暴力, 樹狀數組, 歸併排序, 線段樹, Splay樹來求解。

暴力(187ms):

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 5005;

int n;
int ary[maxn];

int Reverse()
{
    int ret = 0;
    for(int i = 0; i < n; i++){
        for(int k = i +1; k < n; k++){
            ret += (ary[i] > ary[k]);
        }
    }
    return ret;
}

int main()
{
    while(~scanf("%d", &n) && n){
        for(int i = 0; i < n; i++){
            scanf("%d", &ary[i]);
        }
        int ans = Reverse();
        int res = ans;
        for(int i = 0; i < n; i++){
            ans = ans - ary[i] + n - ary[i] - 1;
            res = res < ans ? res : ans;
        }
        printf("%d\n", res);
    }
    return 0;
}

樹狀數組(46ms):

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 5005;

int n;
int ary[maxn];
int tr[maxn];

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

void Insert(int pos)
{
    while(pos <= n){
        tr[pos]++;
        pos += fun(pos);
    }
}

int Query(int l, int r)
{
    int res = 0;
    while(r){
        res += tr[r];
        r -= fun(r);
    }
    l--;
    while(l){
        res -= tr[l];
        l -= fun(l);
    }
    return res;
}

int main()
{
    while(~scanf("%d", &n) && n){
        int ans = 0;
        memset(tr, 0, sizeof(tr));
        for(int i = 0; i < n; i++){
            scanf("%d", &ary[i]);
            Insert(ary[i] + 1);
            ans += Query(ary[i] + 2, n);
        }
        int res = ans;
        for(int i = 0; i < n; i++){
            ans = ans - ary[i] + n - ary[i] - 1;
            res = res < ans ? res : ans;
        }
        printf("%d\n", res);
    }
    return 0;
}

歸併排序(46ms):

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 5005;

int n;
int temp[maxn];
int ary[maxn], cnt[maxn];

int Sort(int l, int mid, int r)
{
    int ret = 0, pos = l;
    int i = l, k = mid + 1;
    while(i <= mid && k <= r){
        if(ary[i] <= ary[k]){
            temp[pos++] = ary[i++];
        }else{
            temp[pos++] = ary[k++];
            ret += mid - i + 1;
        }
    }
    while(i <= mid){
        temp[pos++] = ary[i++];
    }
    while(k <= r){
        temp[pos++] = ary[k++];
    }
    for(i = l; i <= r; i++){
        ary[i] = temp[i];
    }
    return ret;
}

int MergerSort(int l, int r)
{
    if(l >= r)
        return 0;
    int ret = 0;
    int mid = (l + r) >> 1;
    ret += MergerSort(l, mid);
    ret += MergerSort(mid + 1, r);
    ret += Sort(l, mid, r);
    return ret;
}

int main()
{
    while(~scanf("%d", &n) && n){
        for(int i = 0; i < n; i++){
            scanf("%d", &ary[i]);
            cnt[i] = ary[i];
        }
        int ans = MergerSort(0, n - 1);
        int res = ans;
        for(int i = 0; i < n; i++){
            ans = ans - cnt[i] + n - cnt[i] - 1;
            res = res < ans ? res : ans;
        }
        printf("%d\n", res);
    }
    return 0;
}

線段樹(78ms):

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 5005;

struct Tree{
    int l, r, sum;
};

int n;
int ary[maxn];
Tree tr[maxn << 2];


void Build(int rt, int l, int r)
{
    tr[rt].l = l;
    tr[rt].r = r;
    tr[rt].sum = 0;
    if(l == r)
        return ;
    int mid = (l + r) >> 1;
    Build(rt << 1, l, mid);
    Build(rt << 1 | 1, mid + 1, r);
}

void Insert(int rt, int pos)
{
    tr[rt].sum ++;
    if(tr[rt].l == tr[rt].r)
        return ;
    int mid = (tr[rt].l + tr[rt].r) >> 1;
    if(pos <= mid)
        Insert(rt << 1, pos);
    else
        Insert(rt << 1 | 1, pos);
}

int Query(int rt, int l, int r)
{
    if(tr[rt].l > r || tr[rt].r < l)
        return 0;
    if(tr[rt].l >= l && tr[rt].r <= r)
        return tr[rt].sum;
    return Query(rt << 1, l, r) + Query(rt << 1 | 1, l, r);
}

int main()
{
    while(~scanf("%d", &n) && n){
        int ans = 0;
        Build(1, 0, n - 1);
        for(int i = 0; i < n; i++){
            scanf("%d", &ary[i]);
            Insert(1, ary[i]);
            ans += Query(1, ary[i] + 1, n - 1);
        }
        int res = ans;
        for(int i = 0; i < n; i++){
            ans = ans - ary[i] + n - ary[i] - 1;
            res = res < ans ? res : ans;
        }
        printf("%d\n", res);
    }
    return 0;
}

Splay(156ms):
居然只比暴力快一點。。。。

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 5005;

struct Tree{
    int pre, chd[2];
    int val, Size, sum;
    void SetTree(int val, int Size, int sum, int pre, int chd0, int chd1){
        this->val = val;
        this->sum = sum;
        this->pre = pre;
        this->Size = Size;
        this->chd[0] = chd0;
        this->chd[1] = chd1;
    }
};

int n;
int cut[maxn];
Tree tr[maxn];

int F(int rt){
    return tr[tr[rt].pre].chd[1] == rt;
}

void PushUp(int rt)
{
    tr[tr[rt].chd[0]].pre = rt;
    tr[tr[rt].chd[1]].pre = rt;
    tr[rt].Size = tr[tr[rt].chd[0]].Size + tr[tr[rt].chd[1]].Size + 1;
    tr[rt].sum = tr[tr[rt].chd[0]].sum + tr[tr[rt].chd[1]].sum + (tr[rt].val != 0);
}


void Rotate(int rt)
{
    int chd = F(rt);
    int pre = tr[rt].pre;
    tr[rt].pre = tr[pre].pre;
    tr[tr[pre].pre].chd[F(pre)] = rt;
    tr[pre].chd[chd] = tr[rt].chd[!chd];
    tr[rt].chd[!chd] = pre;
    PushUp(pre);
    PushUp(rt);
}

int Splay(int rt, int rw)
{
    while(tr[rw].pre != rt){
        int pre = tr[rw].pre;
        if(F(rw) != F(pre) || tr[pre].pre == rt){
            Rotate(rw);
        }else{
            Rotate(pre);
            Rotate(rw);
        }
    }
    if(rt)
        PushUp(rt);
    return rw;
}

int Insert(int rt, int  pos, int val)
{
    int ret = rt;
    if(tr[tr[rt].chd[0]].Size == pos - 1){
        tr[rt].val = val;
    }else if(tr[tr[rt].chd[0]].Size >= pos){
        ret = Insert(tr[rt].chd[0], pos, val);
    }else{
        ret = Insert(tr[rt].chd[1], pos - tr[tr[rt].chd[0]].Size - 1, val);
    }
    PushUp(rt);
    return ret;
}

int BuildTree(int Size)
{
    for(int i = 1; i < Size; i++){
        tr[i].SetTree(0, Size - i + 1, 0, i - 1, 0, i + 1);
    }
    tr[0].SetTree(0, 0, 0, 0, 0, 0);
    tr[Size].SetTree(0, 1, 0, Size - 1, 0, 0);
    return 1;
}


int main()
{
    int rt;
    while(~scanf("%d", &n) && n){
        int res = 0;
        rt = BuildTree(n + 2);
        rt = Splay(0, n + 2);
        for(int i = 0; i < n; i++){
            scanf("%d", &cut[i]);
            int pos = Insert(rt, cut[i] + 2, cut[i] + 2);
            rt = Splay(0, pos);
            res += tr[tr[rt].chd[1]].sum;
        }
        int minn = res;
        for(int i = 0; i < n; i++){
            minn = minn - cut[i] + n - cut[i] - 1;
            res = res < minn ? res : minn;
        }
        printf("%d\n", res);
    }
    return 0;
}
發佈了117 篇原創文章 · 獲贊 20 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章