1027 Larry and Inversions (35 分)

1027 Larry and Inversions (35 分)

又要找工作開始刷題了(等大佬內推),這道題題意很簡單,給一個1到N的數字的隨機順序數組,若分別將所有的子數組逆序表示,求所有的逆序數。

暴力解法

暴力做法很簡單,只需先求總數組A的逆序數,在考慮子數組中的逆序數就好了。假設原數組的逆序數RV(0,N)爲NA,子數組大小爲N,總組合數爲N×(N-1)/2,子數組逆序數RV(i,j)爲M,那麼反向後逆序數爲N*(N-1)/2-M,和原來的差距爲N*(N-1)/2-M-M=N*(N-1)/2-2M,那麼解答爲NA+N(N-1)/2-2*M。求逆序數RV(i,j)的算法暴力解法(N2)遍歷即可。暴力解法可以過兩個點。這樣每做一個子數組複雜度爲O(N2),總複雜度爲O(N4 )。

解法

關鍵點在於求解逆序數,求解逆序數時,可以看到RV(i,j),與RV(i,j-1)其實只差一個數字。那麼如果我們每次求解RV(i,j)時,只把A[j]和A[i-j]作對比,記錄那些A[j]<A[i-j]的數,每次求解RV(i,j)最壞情況只需要O(N),那麼總複雜度則爲O(N3)。
但是這對於1000的數組來說還是太大,我們引進樹狀數組,數狀數組是一種查詢爲O(log(N))的數據結構,我們可以藉助它查詢A[i-j]中大於A[j]的個數而只需要O(log(N))的時間複雜度,那麼總時間複雜度爲O(N2log(N)),正解。

#include <vector>
#include <iostream>
using namespace std;
int dis[1002][1002];
class TreeArray{
public:
    TreeArray(){arr=vector<int>(1002);};
    void insert(int t){
        while(t<1002){
            arr[t]+=1;
            t+=lowbit(t);
        }
    }
    void init(){
        for(int i=0;i<1002;i++){
            arr[i]=0;
        }
    }

    int getSum(int t){
        int sum=0;
        while(t>0){
            sum+=arr[t];
            t-=lowbit(t);
        }
        return sum;
    }
    inline int lowbit(int t){
        return (t&-t);
    }
    vector<int> arr;
};
void init(){
    for(int i=0;i<1001;i++){
        for(int j=0;j<1001;j++)
            dis[i][j]=0;
    }
}
int main(){
    TreeArray tr;
    init();
    int N;
    cin>>N;
    int temp;
    vector<int> num;
    for(int i=0;i<N;i++){
        cin>>temp;
        num.push_back(temp);
    }
    long long numReverse=0;
    for(int i=0;i<num.size();i++){
        dis[i][i]=0;
        tr.init();
        tr.insert(num[i]);
        for(int j=i+1;j<num.size();j++){
            if(num[i]>num[j]){
                numReverse++;
                
            }
            else{
            }
            dis[i][j]=dis[i][j-1]+j-i-tr.getSum(num[j]);
            tr.insert(num[j]);
        }
    }
    for(int i=0;i<num.size();i++){
        cout<<numReverse;
        if(i!=num.size()-1)
        cout<<" ";
        long long change=0;
        for(int j=i+1;j<num.size();j++){
            change=((j-i+1)*(j-i))/2-2*dis[i][j];
            cout<<change+numReverse<<" ";
            
        }
    }


}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章