1. 程式人生 > >lyd讀書筆記 0x05 排序(下)

lyd讀書筆記 0x05 排序(下)

終於看到了完結的曙光。。話說我規劃今天做後面的題誒。。

k大數

隨機選取一個數,將比它大的放在左邊,小的放在右邊,設有cnt個比它小的,kcnt就在左半段找,否則去右半段。這樣遞迴即可,複雜度O(n)
萬能的STL有nth_element()

分治排序與逆序對

#include <iostream>
using namespacestd;
int n, s, a[100005], t[100005], i;
void mergesort(int l, int r)
{
    if (l == r)
        return;
    int
mid = (l + r) / 2; int p = l; int i = l; int j = mid + 1; mergesort(l, mid); mergesort(mid + 1, r); while (i <= mid && j <= r) { if (a[j] < a[i]) { s += mid – i + 1; t[p] = a[j]; p++; j++; } else
{ t[p] = a[i]; p++; i++; } } while (i <= mid) { t[p] = a[i]; p++; i++; } while (j <= r) { t[p] = a[j]; p++; j++; } for (i = l; i <= r; i++) a[i] = t[i]; } int
main() { cin >> n; for (i = 1; i <= n; i++) cin >> a[i]; mergesort(1, n); cout << s << endl; return 0; }

覺不覺得這個程式碼有點熟悉。。
其實這個程式碼是2017初賽程式填空T3的程式碼。。原封不動的拿過來了。。

原理這裡稍微解釋一下吧,重點是merge的部分。
首先我們考慮一下,如果不進行求逆序對,那麼我們的過程是怎樣的。其實很簡單,我們建兩個指標然後滾一遍,碰到下一個數就比較大小。顯而易見的這個時候我們的兩個子陣列是已經排序完成的,所以直接維護即可。當然如果到最後發現還有一個數組有剩餘,就直接放在最後。

那麼我們考慮哪些地方對逆序對有貢獻。顯而易見的,一個是子陣列內部,一個是兩個陣列之間。但是我們知道,對於一個遞迴過程而言,子陣列內部的一定已經處理完畢了,所以只需要考慮兩個子陣列之間的貢獻,那做法就很顯然了,如果第二個陣列的元素比第一個陣列的某個元素要小,就意味著這個元素比第一個陣列剩餘元素都要小,所以我們加上midi+1個元素。

當然順序對也是同理的,我們考慮第一個陣列對第二個陣列的貢獻即可。這樣的複雜度是O(nlogn)的。

模板題:POJ2299,記得開LL。。

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

using namespace std;

#define N 500005
int a[N], c[N], t;
long long cnt;

void merge(int l, int r) {
    if(l == r) return;
    int mid = l + r >> 1;
    merge(l, mid);
    merge(mid + 1, r);
    int i = l, j = mid + 1, p = l;
    while(i <= mid && j <= r) {
        if(a[i] > a[j]) {
            cnt += mid - i + 1;
            c[p] = a[j]; 
            ++j; ++p;
        } else {
            c[p] = a[i];
            ++i; ++p;
        }
    }
    if(i <= mid) 
        for(int k = i; k <= mid; ++k)
            c[p++] = a[k];
    if(j <= r)
        for(int k = j; k <= r; ++k)
            c[p++] = a[k];
    for(int k = l; k <= r; ++k) a[k] = c[k];
} 

int main() {
    int n;
    while(~scanf("%d", &n)) {
        if(n == 0) break;
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        merge(1, n);
        printf("%lld\n", cnt);
        cnt = 0;
    }
    return 0;
}

奇數碼先打lazytag了。。。