【無聊の瞎搞】倍增歸併
阿新 • • 發佈:2021-10-20
我不知道是否有人之前搞過這種東西
就是一個...倍增寫的歸併排序,好像並沒有必要
時間複雜度 \(O(n \log_2 n)\),這裡的 \(n=2^k\)
如果一個序列長度為 \(m\),則 \(n\) 為最小的 \(2^k \ge m\)
基本思路:
好像沒什麼可以講的
實現:
1、用 \(- \infty\) 把序列湊成一個長度 \(2\) 的冪的序列,然後設定步長 \(step = 1\)
2、設指向區間起始點的 \(i = 1\)
3、合併 \(2\) 個序列,第一個為 \(i\) ~ \(i + \dfrac{step}{2} - 1\),第二個為 \(i + \dfrac{step}{2}\)
4、重複執行 \(2\) 步,每次 \(i=i+step\),直到 \(i > m\)
5、賦值回原序列
6、重複執行 \(2\) 步,每次 \(step=2step\),直到 \(step > m\)
7、輸出除 \(- \infty\) 的序列
把序列湊成一個長度 \(2\) 的冪的序列是為了方便計算,也好寫
Code:
/*Copyright (C) 2013-2022 LZE*/ #include<bits/stdc++.h> #define INF 0x7fffffff using namespace std; typedef unsigned long long ull; typedef long long ll; const int N = 1000010; ll T,n,m; ll a[N] = {0},b[N] = {0}; int main(){ scanf("%lld",&n); for(ll i = 1;i <= n;i++)scanf("%lld",&a[i]); ll p,lp,rp,limit = 1; for(ll i = 1;limit < n;i++)limit = limit * 2; ll bot = limit - n + 1; for(ll i = n + 1;i <= limit;i++)a[i] = -INF; for(ll step = 1;step <= limit;step = step * 2){ for(ll i = 1;i <= limit;i = i + step){ p = 1,lp = i,rp = i + step / 2; for(ll j = 1;j <= step;j++,p++){ if(lp == i + step / 2){ b[p] = a[rp]; rp++; } else if(rp == i + step){ b[p] = a[lp]; lp++; } else if(a[lp] <= a[rp]){ b[p] = a[lp]; lp++; } else if(a[lp] > a[rp]){ b[p] = a[rp]; rp++; } } for(ll j = i,k = 1;k < p;j++,k++)a[j] = b[k]; } } for(ll i = bot;i < n + bot;i++)printf("%lld ",a[i]); printf("\n"); return 0; }