1. 程式人生 > >POJ-3579 Median---二分第k大(二分套二分)

POJ-3579 Median---二分第k大(二分套二分)

else http const AR 最優解 AI 之間 med turn

題目鏈接:

https://cn.vjudge.net/problem/POJ-3579

題目大意:

求的是一列數所有相互之間差值的序列的最中間的值是多少。

解題思路:

可以用二分套二分的方法求解第m大,和POJ-3685類似,這裏的模板也差不多

枚舉第m大x,判斷小於等於x的數目是不是大於m,如果大於m說明x >= 第m大,調整區間r = mid - 1

不然l = mid + 1

此處是大於m而不是小於m是因為一個數可能出現多次,那麽小於等於中間的數目可能就比m大

在計算小於等於x的數目的時候,用upperlower函數求解即可

一開始TLE是因為左右區間沒選好,應該選給定的數字中的最大值減最小值作為右區間

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<cstring>
 6 using namespace std;
 7 typedef long long ll;
 8 const ll INF = 1e9 + 7;
 9 const int maxn = 1e6 + 10;
10 ll a[maxn], n, m;
11 
12 ll ok(ll mid)
13 {
14     ll ans = 0
; 15 for(int i = 1; i < n; i++)//此處不等於n是由於到了n沒有比它更大的了,加上=也無妨 16 { 17 if(a[i] + mid >= a[n])//可以加速一點 18 { 19 ans += n - i; 20 continue; 21 } 22 int t = upper_bound(a + i, a + n + 1, a[i] + mid) - a;//這裏用區間a+i而不是a+1可以加速求解 23 ans += t - 1
- i; 24 } 25 return ans; 26 } 27 int main() 28 { 29 while(scanf("%lld", &n) != EOF) 30 { 31 for(int i = 1; i <= n; i++)scanf("%lld", &a[i]); 32 sort(a + 1, a + n + 1); 33 m = n * (n - 1) / 2; 34 m = (m + 1) / 2;//求出第m個 35 ll l = 0, r = a[n] - a[1], ans; 36 while(l <= r) 37 { 38 ll mid = (l + r) / 2; 39 if(ok(mid) >= m)//小於等於mid的數字個數 >= m 說明mid>=最優解 40 { 41 ans = mid; 42 r = mid - 1; 43 } 44 else l = mid + 1; 45 } 46 printf("%lld\n", ans); 47 } 48 return 0; 49 }

POJ-3579 Median---二分第k大(二分套二分)