链接:https://ac.nowcoder.com/acm/contest/1034/B
来源:牛客网
题目描述
在一片广袤无垠的原野上,散落着N块磁石。
每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径。
若磁石A与磁石B的距离不大于磁石A的吸引半径,并且磁石B的质量不大于磁石A的磁力,那么A可以吸引B。
小取酒带着一块自己的磁石L来到了这片原野的(x0,y0)(x_0,y_0)(x0,y0)处,我们可以视磁石L的坐标为(x0,y0)(x_0,y_0)(x0,y0)。
小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。
在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)(x_0,y_0)(x0,y0)处吸引更多的磁石。
小取酒想知道,他最多能获得多少块磁石呢?
每个磁石的性质可以用一个五元组(x,y,m,p,r)描述,其中x,y表示其坐标,m是磁石的质量,p是磁力,r是吸引半径。
若磁石A与磁石B的距离不大于磁石A的吸引半径,并且磁石B的质量不大于磁石A的磁力,那么A可以吸引B。
小取酒带着一块自己的磁石L来到了这片原野的(x0,y0)(x_0,y_0)(x0,y0)处,我们可以视磁石L的坐标为(x0,y0)(x_0,y_0)(x0,y0)。
小取酒手持磁石L并保持原地不动,所有可以被L吸引的磁石将会被吸引过来。
在每个时刻,他可以选择更换任意一块自己已经获得的磁石(当然也可以是自己最初携带的L磁石)在(x0,y0)(x_0,y_0)(x0,y0)处吸引更多的磁石。
小取酒想知道,他最多能获得多少块磁石呢?
输入描述:
第一行五个整数x0,y0,pL,rL,Nx_0,y_0,p_L,r_L,Nx0,y0,pL,rL,N,表示小取酒所在的位置,磁石L磁力、吸引半径和原野上散落磁石的个数。
接下来N行每行五个整数x,y,m,p,r,描述一块磁石的性质。
输出描述:
输出一个整数,表示最多可以获得的散落磁石个数(不包含最初携带的磁石L)。
示例1
输入
0 0 5 10 5
5 4 7 11 5
-7 1 4 7 8
0 2 13 5 6
2 -3 9 3 4
13 5 1 9 9
输出
3
备注:
1≤N≤250000,1\leq N\leq 250000,1≤N≤250000,
−109≤x,y≤109,−10^9\leq x,y\leq 10^9,−109≤x,y≤109,
1≤m,p,r≤1091\leq m,p,r\leq 10^91≤m,p,r≤109
1)暴力遍历时间复杂度大概在O(n^2),也就是说数据规模超过5000就会TLE,那么很明显这个方法不行
2)考虑排序,按照与(x0,y0)的距离从小到大排序,这个时候算法的时间虽有减少,但是依旧会TLE
3)2中超限大概原因就是要遍历每个d之内的所有数据,因为存在质量与吸引力之间的关系,所以要考虑每个磁石的质量,就会耽误时间
4)既然3中分析出来是因为质量的原因那么我们可以对质量也进行处理,直接1-n排序没有什么意义,联想到用分块排序,在块内对数据进行质量排序
5)排好序后利用,bfs框架对所有能队头磁铁被吸引的磁铁进行入队操作,知道队列为空
6)分块的好处是在前k-1个块内直接只需要比较质量移动块的L[i]即可
完成数据分块的代码值得注意:
1 int cnt = 0, len = sqrt(n); 2 for (int i = 1; i <= n; i += len) { 3 lef[++cnt] = i; 4 rig[cnt] = min(n, i + len - 1); 5 maxdis[cnt] = mag[rig[cnt]].d; 6 sort(mag + lef[cnt], mag + 1 + rig[cnt], cmp_m); 7 }
但是wrong了很多次,因为,ll p = mag[s].p;,本该将p定义为long long ,粗心写成了int
AC代码如下:
1 #include <cmath> 2 #include <queue> 3 #include <cstdio> 4 #include <algorithm> 5 #define ll long long 6 using namespace std; 7 8 const int N = 250005; 9 struct node { 10 ll d, m, p, r; 11 }mag[N]; 12 ll maxdis[510]; 13 int lef[510], rig[510], vis[N]; 14 15 bool cmp_d(node a, node b) { 16 return a.d < b.d; 17 } 18 bool cmp_m(node a, node b) { 19 return a.m < b.m; 20 } 21 22 int main(void) 23 { 24 int n; 25 ll sx, sy; 26 scanf("%lld%lld%lld%lld%d", &sx, &sy, &mag[0].p, &mag[0].r, &n); 27 mag[0].r *= mag[0].r; 28 29 ll x, y; 30 for (int i = 1; i <= n; i++) { 31 scanf("%lld%lld%lld%lld%lld", &x, &y, &mag[i].m, &mag[i].p, &mag[i].r); 32 mag[i].d = (x - sx) * (x - sx) + (y - sy) * (y - sy); 33 mag[i].r *= mag[i].r; 34 } 35 36 sort(mag + 1, mag + 1 + n, cmp_d); 37 38 int cnt = 0, len = sqrt(n); 39 for (int i = 1; i <= n; i += len) { 40 lef[++cnt] = i; 41 rig[cnt] = min(n, i + len - 1); 42 maxdis[cnt] = mag[rig[cnt]].d; 43 sort(mag + lef[cnt], mag + 1 + rig[cnt], cmp_m); 44 } 45 46 int ans = -1; 47 queue<int>q; 48 q.push(0); 49 vis[0] = 1; 50 while (!q.empty()) { 51 int s = q.front(); 52 q.pop(); 53 ++ans; 54 ll u = mag[s].r;//引力半径 55 ll p = mag[s].p;//引力 56 57 for (int i = 1; i <= cnt; i++) { 58 if (maxdis[i] <= u) { 59 for (int& j = lef[i]; j <= rig[i] && mag[j].m <= p; j++) { 60 if (!vis[j]){ 61 q.push(j); 62 vis[j] = 1; 63 } 64 } 65 } 66 else { 67 for (int j = lef[i]; j <= rig[i]; j++) { 68 if (!vis[j] && mag[j].m <= p && mag[j].d <= u) { 69 vis[j] = 1; 70 q.push(j); 71 } 72 } 73 break; 74 } 75 } 76 } 77 printf("%d\n", ans); 78 79 return 0; 80 }
浙公网安备 33010602011771号