题目:华为杯“华南理工大学程序设计竞赛(同步赛) A KNN算法
参考:“华为杯“华南理工大学程序设计竞赛(同步赛)题解A——二分的深入理解
思路
思路挺好想的,二分枚举答案,判断距离为mid时是否满足范围内刚好有k个点
但是赛场了调了很久…果然我不会二分
注意点
1.lower_bound和upper_bound:
lower_bound返回的是第一个大于等于目标值的迭代器。
upper_bound返回的是第一个大于目标值的迭代器。
如果目标值在序列中有多个,lower_bound返回的是第一个目标值的迭代器,而upper_bound返回的是最后一个目标值的下一个迭代器。
现在我们要求所有坐标落在[x-mid, x+mid]
范围内的点的个数
lc
表示第一个坐标大于等于x-mid
的点的下标
rc
表示第一个坐标大于x+mid
的点的下标(也就是最后一个坐标小于等于x+mid
的点的下标(设为rct)+1)
那么rc-lc
就是所求
(其实所有满足条件的点下标在[lc, rtc]之间,个数就是rct - lc + 1
,也就是rc - lc
)
2.l和r的初值
l和r的初值其实就是答案的可能取值,由于坐标范围是[-1e9, 1e9]
,所以答案的取值是[0, 2e9]
,l取0,r取2e9
3.开long long
在二分过程中l和r的取值范围是[0, 2e9]
,l+r是会爆int的,所以l、r、mid都要开long long
因为这个wa了好多好多发…甚至过几天重新来理才反应过来
代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int a[N];
int main()
{
int n, q;
cin >> n >> q;
for (int i = 0; i < n; i++)
cin >> a[i];
sort(a, a + n);
while (q--)
{
int x, k;
cin >> x >> k;
ll l = 0, r = 2e9;
while (l < r)
{
ll mid = l + r >> 1;
int lc = lower_bound(a, a + n, x - mid) - a;
int rc = upper_bound(a, a + n, x + mid) - a;
if (rc - lc >= k)
r = mid;
else l = mid + 1;
}
cout << l << endl;
}
return 0;
}