
双重二分搜索:对列数X计算∣Xi – Xj∣组成新数列的中位数。
3.1不光是查找值!“二分搜索”
查找第k大的值
对X排序后,与X_i的差大于mid(也就是某个数大于X_i + mid)的那些数的个数如果小于N / 2的话,说明mid太大了。以此为条件进行第一重二分搜索,第二重二分搜索是对X的搜索,直接用lower_bound实现。
#ifndef ONLINE_JUDGE
#pragma warning(disable : 4996)
#endif
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long ULL;
#define MAX_N 100000 + 16
ULL N;
ULL C_N_2;
int X[MAX_N];
// mid作为中位数是否太大
bool C(const int& mid)
{
	ULL bigger_count = 0;
	for (int i = 0; i < N; ++i)
	{
		bigger_count += X + N - lower_bound(X + i + 1, X + N, mid + X[i]);	// 返回大于或等于val的第一个元素位置
	}
	return bigger_count <= C_N_2 / 2;
}
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif
	while (cin >> N)
	{
		for (int i = 0; i < N; ++i)
		{
			scanf("%d", X + i);
		}
		sort(X, X + N);
		C_N_2 = N * (N - 1) / 2;
		ULL lb = 0, ub = *max_element(X, X + N) - *min_element(X, X + N) + 1;
		while (ub - lb > 1)
		{
			int mid = (lb + ub) >> 1;
			if (C(mid))
			{
				ub = mid;
			}
			else
			{
				lb = mid;
			}
		}
		cout << lb << endl;
	}
#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
	system("out.txt");
#endif
	return 0;
}
///////////////////////////End Sub//////////////////////////////////
| 12835934 | hankcs | 3579 | Accepted | 360K | 579MS | C++ | 1190B | 2014-05-04 03:11:35 | 
码农场
题主,C()那里可以用尺取法来计算小于等于mid的个数 =V= 时间可以少一半
int p = 0;
for(int i = 1; i < N; i++){
for(int j = p; j < i; j++){
if(X[i] – X[j] <= x){
res += i – j;
p = j;
break;
}
}
}
return res;
不好意思,if里的x就是mid
根据题目描述,好像这组数据是过不了的:
2
-1000000000 1000000000
我的AC程序也过不了这组数据,始终不知道如果考虑这组数据的话,怎样才能过掉题目而且还不会TLE。。请问博主有什么好的想法么??
ub的初始值小了而已,有负数的情况下改成
int lb = 0, ub = *max_element(X, X + N) – *min_element(X, X + N) + 1;
就行了。另外1000000000会溢出,改成ULL就行了。
表示本弱就是这样做的, 然后TLE无数。。T^T,总感觉自己姿势不对。。