求逆序對數(氣泡排序交換次數)
阿新 • • 發佈:2019-02-02
求 a1,a2,..,an 的逆序對數
一、直接求
直接兩個for迴圈跑
時間複雜度 O(n^2)
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[i]>a[j]) cnt++;
}
}
二、樹狀陣列(或線段樹)求
建一個樹狀陣列或線段樹,存每個數出現的個數,每次詢問後加入,數比較大的情況下要離散化。
對於ai來說,它作為逆序對較小部分時的逆序對數 = 在ai前面比ai大的數的個數。
時間複雜度 O(n*logn)
for(int i=1;i<=n;i++){ ans += Sum(mx) - Sum(a[i]); add(a[i]); }
三、分治法求(歸併排序)
可以將整個序列平分為兩個部分分別排序,然後再將其合併,合併過程中計算逆序對數
設分開的兩個序列排序完後分別為a1,a2,..,an/b1,b2,..,bn
合併中要使得新序列有序,若bi<aj 則 bi 要排在aj前面,而bi在初始狀態的位置在aj後面,則逆序對數+(n-j+1)
就是一個二分遞推的過程
時間複雜度 O(n*logn)
void merge(int L,int R){ int pos1 = L, pos2 = mid+1; int b[N],i = L; while(pos1<=mid&&pos2<=R){ if(a[pos1]<=a[pos2]) b[i++] = a[pos1++]; else {b[i++] = a[pos2++]; ans += mid+1-pos1;} } while(pos1<=mid) b[i++] = a[pos1++]; while(pos2<=R) b[i++] = a[pos2++]; for(int i=L;i<=R;i++) a[i] = b[i]; } void sort(int L,int R){ if(L==R) return; sort(L,mid); sort(mid+1,R); merge(L,R); }