提高模擬賽Day8T1求中位數
阿新 • • 發佈:2021-11-08
題目
\(n\)個數\(a_{1\ldots n}\),兩兩做差(大減小),得到陣列\(b\),求\(b\)的中位數.
思路
對原陣列排序,二分列舉中位數\(mid\),求有多少個做差陣列中比\(mid\)大/小的數分別由多少個,時間複雜度是\(O(n\log^2n)\),可以卡過去.
正解是雙指標?
程式碼
//#pragma GCC optimize(2) #include <iostream> #include <cstdio> #include <algorithm> #include <vector> #define int long long using namespace std; int read() { int re = 0; char c = getchar(); bool negt = false; while(c < '0' || c > '9')negt |= (c == '-') , c = getchar(); while(c >= '0' && c <= '9')re = (re << 1) + (re << 3) + c - '0' , c = getchar(); return negt ? -re : re; } const int N = 2e5 + 10; int abs_(int a) { return a < 0 ? -a : a; } int n , m; int a[N]; vector <int> ans; int check(int val) { //return 0(too small) 1(too big) 2(find answer) int sm = 0 , bg = 0; int v , l , r; for(int i = 1 ; i <= n ; ++i) { v = a[i] + val; l = lower_bound(a + 1 , a + n + 1 , v) - a , r = upper_bound(a + 1 , a + n + 1 , v) - a; if(a[l] >= v || l == n + 1)--l; sm += max(0ll , l - i) ; bg += n - r + 1; } int equ = m - sm - bg; if(sm >= (m + 1) / 2)return 1; if(sm + equ < (m + 1) / 2)return 0; if(equ == 0)return 0; ans.push_back(val); return 2; } int check2(int val) { //return 0(too small) 1(too big) 2(find answer) int sm = 0 , bg = 0; int v , l , r; for(int i = 1 ; i <= n ; ++i) { v = a[i] + val; l = lower_bound(a + 1 , a + n + 1 , v) - a , r = upper_bound(a + 1 , a + n + 1 , v) - a; if(a[l] >= v || l == n + 1)--l; sm += max(0ll , l - i) ; bg += n - r + 1; } int equ = m - sm - bg; if(sm >= m / 2 + 1)return 1; if(sm + equ < m / 2 + 1)return 0; if(equ == 0)return 0; ans.push_back(val); return 2; } signed main() { // freopen("mid.in" , "r" , stdin); // freopen("mid.out" , "w" , stdout); n = read() , m = n * (n - 1) / 2; for(int i = 1 ; i <= n ; i++) a[i] = read(); sort(a + 1 , a + n + 1); int l = 0 , r = 1ll << 31; while(l <= r) { int mid = (l + r) / 2; int tmp = check(mid); if(tmp == 2)break; if(tmp == 0)l = mid + 1; else r = mid - 1; } if((m & 1) == 0) {//有兩個中位數 l = 0 , r = 1ll << 31; while(l <= r) { int mid = (l + r) / 2; int tmp = check2(mid); if(tmp == 2)break; if(tmp == 0)l = mid + 1; else r = mid - 1; } } int sum = 0; for(int i : ans) sum += i; cout << sum / ans.size(); return 0; }