1. 程式人生 > >ural1090 逆序對(歸併排序和樹狀陣列)

ural1090 逆序對(歸併排序和樹狀陣列)

題意:

在軍隊中

軍官命令新兵排行成列。新兵們排成了K行,每行有N人。但有K人沒有排在正確的位置上。

正確的排隊位置如下:第一個士兵必須是最高的,第二個是第二高的,依此類推,最後一個士兵必須是最矮的。為了排好隊,軍官規定每一個士兵,如果與他同一排的前一個人比他矮,那麼他就向前跳一步。

注意沒有兩個新兵的身高相同。

軍官想找出哪一排士兵跳的總次數最多,好懲罰他們到廚房去工作。你的目標就是幫助軍官找到這一排。

Input

輸入的第一行包含了兩個數N和K(2≤N≤10000,1≤K≤20)。接下來的K行每行包含N個整數。新兵已經按照身高編好了號(1號最高,N號最矮)。每一行是相應的一排,例如某一行的第一個整數代表這行的第一個人等等。

Output

輸出跳躍次數最多的那一行的編號。如果有幾行次數相同,則輸出行編號最小的那個。

是在個人訓練賽的時候遇到的一道簽到題,求逆序對如果列舉的話時間複雜度是n^2,太大了。一般我們用於求逆序對的方法有兩種,一種是歸併排序,一種是樹狀陣列。歸併排序的程式碼如下:

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

using namespace std;
const int maxn=10000+20;
const int maxk=25;
int G[maxk][maxn];
int n,k,num ;
int t[maxn];
int a[maxn];
void merge_sort(int *A,int L,int R,int *T){
    if(R-L==0)return ;
    int m=L+(R-L)/2;
    merge_sort(A,L,m,T);
    merge_sort(A,m+1,R,T);
    int p=L,q=m+1,i=L;
    while(p<=m||q<=R){
        if((A[p]<A[q]&&p<=m)||q>R)T[i++]=A[p++];
        else{
            T[i++]=A[q++];
            num+=m-p+1;
        }

    }
    for(int i=L;i<=R;i++)A[i]=T[i];
}

int main(){
    cin>>n>>k;
    int ans=-1,ansn=-1;
    for(int i=1;i<=k;i++){
        for(int j=1;j<=n;j++){
            cin>>G[i][j];
        }
          num=0;
         merge_sort(G[i],1,n,t);
         if(ans<num){
            ans=num;ansn=i;
         }
    }
    cout<<ansn;
return 0;
}

這種方法是本來就會的一種方法,很快寫完A掉了,但是從來沒有嘗試過用樹狀陣列來求逆序對。一開始思維受限於歸併的方法,一直在考慮樹狀數組裡存的內容是什麼,後來想到,直接把每個數字樹狀陣列作為下標對於每個數字a,通過樹狀陣列求得比a小的數字有多少。但是發現,因為要直接以每個數字a的值作為樹狀陣列的下標,所以···開不下,於是想了另一種辦法,用一個結構體來儲存每個數字的值,並給他們重新排序,給每個值賦予一個編號mval,mval的範圍位1-n,這樣便可以解決此問題了(查資料瞭解到這個方法叫離散化,而我離散化的寫法非常白痴

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

using namespace std;
const int maxn=10000+10;
const int maxk=25;
struct Num{
    int val,mval,i;
}num[maxn];
int G[maxn],C[maxn] ;
int n,k;
int lowbit(int x){return x&-x;}
int sum(int x){
    int ans=0;
    while(x>0){
      ans+=C[x];
      x-=lowbit(x);
    }
    return ans;
}
int add(int x){
    while(x<=n){
        C[x]+=1;
        x+=lowbit(x);
    }
}
int cmp1(Num a,Num b){
    return a.val<b.val;
}
int cmp2(Num a,Num b){
    return a.i<b.i;
}
int main(){
    cin>>n>>k;
    int ans=-1,ansn=-1;
    for(int i=1;i<=k;i++){
             int ANS=0;
             memset(C,0,sizeof(C));
      for(int j=1;j<=n;j++){
           cin>>num[j].val;
           num[j].i=j;
           }

    sort(num+1,num+1+n,cmp1);
    for(int j=1;j<=n;j++)
        num[j].mval=j;
    sort(num+1,num+1+n,cmp2);
    for(int j=1;j<=n;j++){
        int a=num[j].mval;
        add(a);
        ANS+=(j-sum(a));
    }
            /*cin>>G[i][j];
            add(G[i][j]);
            ANS+=(j-sum(G[i][j]));*/
        //cout<<num<<endl;
      if(ans<ANS){
        ans=ANS,ansn=i;
      }
    }
    cout<<ansn;

return 0;
}