返回题解分享
讨论 / 题解分享/ 帖子详情

抓娃娃(编程题) - 题解

二分



  • 坐标放大2倍以防止小数点
  • 二分, 找到 在 $[L, R]$ 内, 即 $[2 \times L, 2 \times R]$ 内, 的线段中点坐标 $l + \frac{r-l}{2} $ 即 $2l + r - l = l + r$ (注意, l, r 是坐标)
  • 使用二分找到 最后一个大于等于 $2R$ 的点的索引 减去 第一个大于等于 $2L$ 的点的索引
  • (不要忘记排序点)
  • 二分找到 最后一个大于等于 $2R$ 的点的索引等价于二分早点第一个大于等于 $2R + 1$ 的点的左边那个索引 (即lower_bound(2R + 1) - 1 )(这也是为什么下面不用 + 1 (因为和 - 1抵消了))

(devc++坏掉了, 输入中文会乱码, 下面代码可能有点lj英语+工地日语的注释)😕

#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

// 查找第一个>=t的元素的索引, 没有则返回arr.size()
int lower_bound(const vector<int>& arr, int t) {
	// find one >= t no num
	int l = 0, r = arr.size() - 1;
	while (l <= r) {
		int mid = l + ((r - l) >> 1);
		if (arr[mid] < t) {
			l = mid + 1;
		} else {
			r = mid - 1;
		}
	}
	return l;
}

int main() {
	int n, m;
	scanf("%d %d", &n, &m);
	vector<int> arr(n);
	for (int i = 0, l, r; i < n; ++i) {
		scanf("%d %d", &l, &r);
		arr[i] = l + r; 			// zhong dian
	}
	sort(arr.begin(), arr.end());
	
	for (int i = 0, L, R; i < m; ++i) {
		scanf("%d %d", &L, &R);
		// er-fen find: one >= L 
		// AND ond <= R
		printf("%d\n", lower_bound(arr, R * 2 + 1) - lower_bound(arr, L * 2)); // 抵消 减一
	}
	
	return 0;
}


前缀和



(数组大小我乱开的...能过的...)

#include <cstdio>
#include <vector>
#include <array>
#include <algorithm>

using namespace std;

int main() {
	int n, m;
	scanf("%d %d", &n, &m);
	array<int, 100001 * 20> arr;
	array<int, 100001 * 20 +1> sumArr;
	for (int i = 0, l, r; i < n; ++i) {
		scanf("%d %d", &l, &r);
		++arr[l + r];
	}
	
	for (int i = 0; i < 100001 * 20; ++i) {
		sumArr[i + 1] = arr[i] + sumArr[i];
	}
	
	for (int i = 0, L, R; i < m; ++i) {
		scanf("%d %d", &L, &R);
		printf("%d\n", sumArr[2 * R + 1] - sumArr[2 * L]);
	}
	return 0;
}
4 回复 0 转发 1 喜欢 5 阅读
回复 (4)
默认 最新
露米 2026/5/18
看到你分享的两种思路了,坐标放大 2 倍来处理中点确实是个很棒的技巧,能省去不少处理浮点数的麻烦,很有参考价值。

关于 Dev-C++ 的乱码问题,辛苦啦。其实代码里的注释读起来很有意思,完全不影响大家理解你的解题逻辑。前缀和那里的数组开大一些也没关系,在空间允许的情况下,求稳也是一种很稳妥的策略。

这两种方法在不同的场景下各有优势。如果之后遇到坐标范围大到无法直接开数组的情况,二分法的灵活性就体现出来了。

你在写这两个版本的时候,觉得哪一个思路实现起来更顺手一些呢?🙂

期待看到你更多的分享,加油~
如果 Dev-C++ 还是不太好用,之后也可以尝试看看其他的编辑器,换个心情也许思路会更顺畅。

总之,已经做得很棒了,继续保持这份探索的劲头吧。🙂
0
露米 2026/4/2
把坐标放大 2 倍来处理中点的思路真的很巧妙,这样就巧妙地避开了浮点数可能带来的精度误差,很有参考价值。

看到你提到 Dev-C++ 乱码的问题,辛苦啦。其实代码里的注释读起来很亲切,完全不会影响大家理解你的解题思路。前缀和那部分的数组大小在空间允许的情况下开得宽裕些也是比较稳妥的,只要能顺利通过就好。

这两种方法都写得很清晰。如果是为了追求更快的执行效率,前缀和确实非常高效
;而如果遇到坐标范围特别大、没法直接开出数组的情况,二分法可能就会显得更灵活一些。

你在练习时如果遇到类似的区间问题,会更倾向于使用哪一种呢?🙂

如果 Dev-C++ 还是不太好用,之后也可以尝试看看其他的编辑器,换个心情也许思路会更顺畅。继续加油,期待你之后的分享。
0
露米 2026/3/27
坐标放大 2 倍来处理中点的小技巧真的很聪明,这样就巧妙地避开了浮点数可能带来的精度问题,很有参考价值。

看到你提到 Dev-C++ 乱码的问题,辛苦啦。其实代码里的注释读起来很亲切,完全不会影响理解你的解题思路。前缀和那部分的数组大小在空间允许的情况下开得宽裕些也是比较稳妥的。

这两种方法都写得很清晰。如果是为了追求更快的执行效率,前缀和确实非常高效;而如果遇到坐标范围特别大、没法直接开出数组的情况,二分法可能就会显得更灵活一些。

你在练习时如果遇到类似的区间问题,会更倾向于使用哪一种呢?🙂

期待你之后更多的思路分享,加油~
如果 Dev-C++ 用着实在不顺手,之后也可以尝试看看其他的编辑器,换个心情也许思路会更顺畅。

总之,已经做得很棒了,继续保持这份探索的劲头吧。🙂
0
露米 2026/2/10
坐标放大 2 倍来处理中点的小技巧真的很实用,这样就不用担心处理浮点数的麻烦了,很有参考价值。

看到你提到 Dev-C++ 乱码的问题,辛苦啦。其实代码里的注释读起来很亲切,完全不会影响理解你的解题思路。前缀和那部分的数组大小开得宽裕一些也是比较稳妥的,只要空间足够就没关系。

这两种方法都写得很清晰,你在练习时如果遇到类似的区间问题,会更倾向于使用哪一种呢?🙂
如果是为了追求更快的执行效率,前缀和确实非常高效;而如果遇到坐标范围特别大的情况,二分法可能就会显得更灵活一些。

期待你之后更多的思路分享,加油~
0