题意
有 \(n\) 条鱼,\(m\) 个渔夫,且这 \(m\) 个渔夫都在横坐标轴上,每个渔夫都有一个长度为 \(l\) 的鱼竿,当鱼和渔夫距离小于或等于 \(l\) 时,鱼能被钓到。
并且渔夫 \((x,0)\) 与鱼 \((a,b)\) 的距离(假设为 \(L\) )满足如下公式 \(|a − x| + b\) 式子中 \(x\) 为渔夫的横坐标,\((a,b)\) 为鱼的坐标。
求解思路
这道题肯定以鱼为考虑的对象。先对公式 \(|a - x| + b\) 入手。设 \(l ≤ |a - x| + b\)。
可求出鱼能被钓到时渔夫 \(x\) 的一个范围 \(a+l-b \leq x \leq a-l+b\)。
然后把渔夫的位置排个序,遍历所有的鱼,每一条鱼能够被可以被抓都在 \(x\) 轴有一个范围 \((a+l-b \leq x \leq a-l+b)\)。
通过二分,在渔夫中找到最左的和最右的,然后差分一下,最后求个前缀和就可以得出答案。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 7;
struct fish {
int x, y;
} f[maxn];
struct yufu {
int x, id, idd; ///id表示输入时的序号。idd表示排序之后的序号
bool operator <(const yufu &bb)const { ///重载<运算符 为了能够用sort进行排序
return x < bb.x;
}
} ma[maxn];
int sum[maxn], ans[maxn];
int main() {
int n, m, l;
scanf("%d %d %d", &n, &m, &l);
memset(sum, 0, sizeof(sum));
for (int i = 1; i <= n; i++)
scanf("%d %d", &f[i].x, &f[i].y);
for (int i = 1; i <= m; i++) {
scanf("%d", &ma[i].x);
ma[i].id = i;
}
sort(ma + 1, ma + m + 1); ///排序
for (int i = 1; i <= m; i++)
ma[i].idd = i;
for (int i = 1; i <= n; i++) {
if (f[i].y - l > 0) continue; ///当距离超过l时continue掉
yufu tmp;
tmp.x = f[i].x - l + f[i].y; ///二分法
int xx = lower_bound(ma + 1, ma + m + 1, tmp) - ma; ///注意一点用这两个函数时,tmp和ma必须是同类型的
tmp.x = f[i].x + l - f[i].y;
int yy = upper_bound(ma + 1, ma + m + 1, tmp) - ma;
sum[xx]++;
sum[yy]--;
}
for (int i = 1; i <= m; i++) { ///用差分法求前缀和
sum[i] += sum[i - 1];
ans[ma[i].id] = sum[ma[i].idd];
}
for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}
标签:tmp,ma,int,题解,P5867,leq,渔夫,Fishermen
From: https://www.cnblogs.com/BadBadBad/p/P5867.html