题目大意:给平面上n个点,问有多少对点间的距离小于d。
思路:一眼可以看到,虽然x轴和y轴的范围很大,但是d却很小,这应该是一个突破口。
那么这个d怎么利用呢。思考一下,对于任意一个点P,和它的距离小于d的点,至少应该在一个以P为中心的2d*2d的正方形中。
因为要题目要求的是对数,那么我们可以只考虑P点的右半部分的点(因为左边部分的点与P的组合在计算左边的点的时候已经算了)。
那么,我们就是要考虑,对于点P(x0, y0),只考虑x = x0、x0+1、……、x0+d-1的点。
穷举这些x = x0 + i,那么y轴的范围就应该在[y0 - t, y0 + t]之间,其中 t 是满足i^2 + t^2 < d^2的最大整数(注意题目都是整点)。
如果对于每一个x = x0 + i的点我们都可以收集起来,按y轴排好,那么二分查找,可以得到 结果 = 小于等于y0 + t的数目 - 小于y0 - t的数目。
因为x的范围很大,不可能说每个点开个数组,我们可以用C++的map存起来,每个有可能的x开一个vector,然后排序即可(注意找map中是否存在x的时候最好用map.find(x),直接用map[x]会创建一个x留在map中,可能导致效率的减缓)。
如果不用map也不是不可以,只要把点都从小到大(x轴为第一关键字,y轴第二关键字)排好序,每次需要哪个x的时候二分查找也是可以的。
我们好像还没算x轴相同的呢。对于x轴相同的,弄俩指针,从前往后扫就可以统计出来了,这个还是不难的。
细节可以看代码,时间复杂度为O(n*d*log(n))。
代码(14109MS):
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <iostream> 5 #include <map> 6 #include <vector> 7 using namespace std; 8 typedef long long LL; 9 10 const int MAXN = 100010; 11 12 int T, n, d, x, y; 13 map<int, vector<int> > mymap; 14 15 LL solve() { 16 LL ans = 0; 17 for(map<int, vector<int> >::iterator it = mymap.begin(); it != mymap.end(); ++it) { 18 sort(it->second.begin(), it->second.end()); 19 for(int i = 0, j = 0, n = it->second.size(); i < n; ++i) { 20 while(j < n && it->second[i] + d > it->second[j]) ++j; 21 ans += j - i - 1; 22 } 23 } 24 int d2 = d * d; 25 for(map<int, vector<int> >::iterator it = mymap.begin(); it != mymap.end(); ++it) { 26 for(vector<int>::iterator p = it->second.begin(); p != it->second.end(); ++p) { 27 for(int i = 1, t = d; i < d; ++i) { 28 while(i * i + t * t >= d2) --t; 29 map<int, vector<int> >::iterator nx = mymap.find(it->first + i); 30 if(nx != mymap.end()) { 31 ans += (upper_bound(nx->second.begin(), nx->second.end(), *p + t) - nx->second.begin()) - 32 (lower_bound(nx->second.begin(), nx->second.end(), *p - t) - nx->second.begin()); 33 } 34 } 35 } 36 } 37 return ans; 38 } 39 40 int main() { 41 scanf("%d", &T); 42 while(T--) { 43 mymap.clear(); 44 scanf("%d%d", &n, &d); 45 for(int i = 0; i < n; ++i) { 46 scanf("%d%d", &x, &y); 47 mymap[x].push_back(y); 48 } 49 printf("%I64d\n", solve()); 50 } 51 }