1 条题解
-
0
題解 - 回到过去 - 南阳理工学院OJ (nyist.edu.cn) 这是上次的题解,这次的题与上次的题思路大概一致,只不过数据中多了 这个数据
在上次的二分中,我们是枚举 来找到第一个满足的 然后答案 代码如下
#include<stdio.h> long long int a[100005], sum[100005]; int main() { int n, k; scanf("%d%d",&n,&k); for(int i = 1; i <= n; i++) { scanf("%lld",&a[i]); } for(int i = 1; i <= n; i++) { sum[i] = sum[i - 1] + a[i]; } long long cnt = 0; for(int i = 1; i <= n; i++) { int l = 1, r = n, mid; while(l < r) { mid = (l + r) / 2; if(sum[mid] >= sum[i - 1] + k) r = mid; else l = mid + 1; } if(sum[l] - sum[i - 1] >= k) cnt += (n - l + 1); } printf("%lld",cnt); return 0; }
这是上次题解中二分的码,我们的二分边界为 由于上次的数据中没有数据零,所有我们最后二分查找的结果 也就是第一个满足的下标 是一定大于等于 的,所以并不会出现错误。 但如果出现数据零,我们的二分边界要改成 不然我们所查找的下标可能会比 小从而使最终答案比标准答案变多。
例如 此时有这个题目 我们有 数组,里面有 个数,我们想要找到大于等于 且大于等于 的第一个下标
第一行输入 第二行为
5 0 1 3 7 7 9
1 2 3 4 5
for(int i = 1; i <= n; i++) { int l = 1, r = n, mid; while(l < r) { mid = (l + r) / 2; if(a[mid] >= a[i] + x) r = mid; else l = mid + 1; } cout << l << '\n'; }
但这个二分查找的结果却为
这是因为如果我们的二分边界 依然从 开始 那当 时,由于我们的二分查找找的是大于等于 的第一个下标 所以我们会找到第一个 的下标也就是 但我们需要的答案应该时大于等于 的 所以会错 所以我们只需要改一下二分的边界 就可以避免这个错误 因为我们需要找到大于等于 的某个下标 所以我们只需要这么改
for(int i = 1; i <= n; i++) { int l = i, r = n, mid; while(l < r) { mid = (l + r) / 2; if(a[mid] >= a[i] + x) r = mid; else l = mid + 1; } cout << l << '\n'; }
也就是把 改为 这就避免了所找的下标小于 这个问题
ps : 因为想到再次出这个题 并且加上 0 这个数据, 所以在上次的题解中故意将二分边界 改为 而不是 以及在上次的双指针代码中也卡掉了 0 这个数据, 大家可以想想如何对双指针的代码进行修改,从而避免这个数据的错误
有任何问题可以在评论区问
- 1
信息
- ID
- 406
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 20
- 已通过
- 5
- 上传者