一,思路:
1,做这题如果对二分敏感的话,看完题目就大概很容易想到,通过二分来找到一个 r ,使得 [ l, r] 之间的和最接近 u (因为这样才是 Isaac 所能获得的最大提升)。
2,还有一个特殊情况,结合代码来说明。
二,代码
-
- #include <iostream>
- #include<cstring>
- #include<algorithm>
- using namespace std;
-
- const int N = 1e5+10;
- typedef long long ll;
-
- int arr[N];
- ll pre[N];
-
- //u--->题目输入的目标值
- //st---> 题目输入的起始坐标
-
- int u,st;
-
- //重写二分比较函数
- bool check(int mid) {
- if (pre[mid] - pre[st - 1] <= u) return true;
- return false;
- }
-
- void sovle() {
-
-
- int n;
- cin >> n;
- for (int i = 0; i <= n; i++) pre[i] = 0;
-
- for (int i = 1; i <= n; i++) {
- cin >> arr[i];
- pre[i] = pre[i - 1] + arr[i];
- }
-
- int q;
- cin >> q;
- while (q--) {
-
- cin >> st >> u;
- int l=st,r = n;
-
- //二分模板
- while (l < r) {
- int mid = l + r + 1>> 1;
- if (check(mid)) l = mid;
- else r = mid - 1;
- }
-
- //特殊情况:
- // 1.首先要知道,我们求得的 r只是 [l,r]之和小于等于u的那个位置,不一定是最接近的那个点。
- // 2.举个例子:
- // (1)例如 数组:[1 ,2 ,8] ,目标值u = 10 , 起始位置 l = 1。
- (2)这里我们二分求得的是 r =2(1 + 2 = 3 < 10),但是明显 r=3 时更接近 u
-
- // 3.还有个陷阱,就是当他们的差距相等时,是选 r +1 还是 r 呢?如果不仔细分析的话,很容易
- // 就会想当然认为是 r,因为 r < r +1.实则不是,这里我就不举例了,你们自己可以将下面的判断
- // 改成 u - (pre[r] - pre[st - 1]) <= (pre[r + 1] - pre[st - 1]) - u 试一下,看是什么
- // 结果,然后再去找出问题即可。
-
- //判断离目标值最近的点是 r 还是 r +1
- if (r == n || u - (pre[r] - pre[st - 1]) < (pre[r + 1] - pre[st - 1]) - u) {
- cout << r <<" ";
- }
- else cout << r + 1 << " ";
- }
-
- cout << endl;
- }
-
- int main()
- {
- ios::sync_with_stdio(false);
- cin.tie(0);
-
- int t;
- cin >> t;
- while (t--) {
- sovle();
- }
- return 0;
- }