1. 程式人生 > >hihocoder-1524-逆序對

hihocoder-1524-逆序對

+= swe problem clu merge 0ms bit main d+

hihocoder-1524-逆序對

#1524 : 逆序對

時間限制:10000ms 單點時限:1000ms 內存限制:256MB

描述

給定一個1-N的排列A1, A2, ... AN,如果Ai和Aj滿足i < j且Ai > Aj,我們就稱(Ai, Aj)是一個逆序對。

求A1, A2 ... AN中所有逆序對的數目。

輸入

第一行包含一個整數N。

第二行包含N個兩兩不同整數A1, A2, ... AN。(1 <= Ai <= N)

對於60%的數據 1 <= N <= 1000

對於100%的數據 1 <= N <= 100000

輸出

一個整數代表答案

樣例輸入
5
3 2 4 5 1
樣例輸出
5

經典的用merge sort 來解決逆序對的問題。

#include <cstdio> 
const int MAXN = 1e5 + 10; 
const int MOD = 1000000007; 

int  num[MAXN], tmp[MAXN]; 
long long cnt; 

void Merge_Sort(int l, int r){
    int mid = l + (r - l)/2; 
    int p = l, p1 = l, p2 = mid + 1; 
    while(p1<=mid && p2<=r){
        if(num[p1] > num[p2]){
            tmp[p++] = num[p2++]; 
            cnt += (mid - p1 + 1); 
        }else{
            tmp[p++] = num[p1++]; 
        }
    }
    while(p1<=mid){
        tmp[p++] = num[p1++]; 
    }
    while(p2<=r){
        tmp[p++] = num[p2++]; 
    }
    for(int i=l; i<=r; ++i){
        num[i] = tmp[i]; 
    } 
}

void Merge(int l, int r){
    if(l >= r ){ return; } 
    int mid = l + (r - l)/2; 
    Merge(l, mid); 
    Merge(mid+1, r); 
    Merge_Sort(l, r); 
}

int main(){
    int n; 
    while(scanf("%d", &n) != EOF){
        for(int i=0; i<n; ++i){
            scanf("%d", &num[i]); 
        }
        cnt = 0; 
        Merge(0, n-1); 
        printf("%lld\n", cnt );
    }
    return 0; 
}

  

方法二,參考了網友的answer,因為 num 的range 是 [1, n] , 所以,可以采用樹狀數組。只需要對 num 一個一個插入到 dp[] 數組中,快速計算 sum即可。

#include <cstdio> 
#include <cstring>
const int MAXN = 1e5 + 10; 
const int MOD = 1000000007; 

long long cnt; 
int n, num[MAXN], dp[MAXN]; 

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

long long GetSum(int pt){
    long long ans = 0; 
    int i = pt; 
    while(i <= n){
        ans += dp[i]; 
        i +=  lowbit(i); 
    } 
    return ans; 
}

void AddNum(int pt, int v){
    int i = pt; 
    while(i > 0){
        dp[i] += v; 
        i -= lowbit(i); 
    }
}

int main(){
    freopen("in.txt", "r", stdin); 

    while(scanf("%d", &n) != EOF){
        for(int i=0; i<n; ++i){
            scanf("%d", &num[i]); 
        }
        memset(dp, 0, sizeof(dp)); 
        cnt = 0; 
        for(int i=0; i<n; ++i){
            cnt += GetSum(num[i]); 
            AddNum(num[i], 1); 
        }
        printf("%lld\n", cnt );
    }
    return 0; 
}

  

hihocoder-1524-逆序對