这种题一般是给定N个数,然后N个数之间通过某种计算得到了新的数列,求这新的数列的第K大的值
POJ3579
题意:
用$N$个数的序列$x[i]$,生成一个新序列$b$。
新的序列定义为:对于任意的$ i$,$j$且 $i != j $有$b[] = abs(x[i] - x[j])$
问新序列的中位数是什么,如果新序列的长度为偶数那么我们定义中位数为排序后第len/2位置的那个数
解法:
相当于问新序列中的第K大的数多少。
注意新数列不可能全都算出来。
二分答案,二分那个第K大的数的值。
$x[i]-x[j] \ge mid$
相当于
$x[i] \ge mid+x[j]$
然后我们在排序过的原数组中,对每个$a[i]$二分这个$mid$值,统计有多少个值小于它,统计累加所有的值,最后看是不是小于K
代码如下:
1 int N; 2 int a[MAXN]; 3 LL M; 4 5 bool C(int t) { 6 LL cnt = 0; 7 for (int i = 0; i < N; i++) { 8 cnt += N - (lower_bound(a + i + 1, a + N, a[i] + t) - a); 9 } 10 return cnt <= M / 2; 11 } 12 13 void solve() { 14 sort(a, a + N); 15 M = N * (N - 1) / 2; 16 int ub = a[N - 1] + 1, lb = 0; 17 while (ub - lb > 1) { 18 int mid = (ub + lb) >> 1; 19 if (C(mid)) { 20 ub = mid; 21 } else { 22 lb = mid; 23 } 24 } 25 cout << lb << endl; 26 return; 27 } 28 29 int main() { 30 #ifndef ONLINE_JUDGE 31 freopen("input.txt", "r", stdin); 32 #endif // !ONLINE_JUDGE 33 while (~scanf("%d", &N)) { 34 for (int i = 0; i < N; i++) { 35 scanf("%d", &a[i]); 36 } 37 solve(); 38 } 39 return 0; 40 }