题目
思路
- 扩大数据,避免精度问题,拉到整数域解决
- 不用枚举前缀和的 l 和 r,改为求可能 l 的最小值,线性做法
- 不用记录长度来求平均值,改为用平均值处理数据(这是第二条的前提),直接通过和的正负来判断不等关系
这个表达式只有两个变量。
所以判断是否存在一组 和 ,不需要枚举所有的组合。
可以维护一个 到 的最小值 (线性)。
我们枚举 即可覆盖可能的最大差值。
而如果不这样处理,我们的判断方式其实是:
这个表达式有多个变量,不好处理。
扩大数据,整数二分代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
ll a[N], s[N];
int n, f;
bool check(int mid)
{ll minv = 0;for(int i = 1; i <= n; i++)s[i] = a[i] - mid + s[i-1];for(int i = f; i <= n; i++){minv = min(minv, s[i-f]);if(s[i] - minv >= 0) return true;}return false;
}
int main()
{cin >> n >> f;for(int i = 1; i <= n; i++)cin >> a[i], a[i] *= 1000;int l = 1, r = 2e6;while(l < r){int mid = (l + r + 1) >> 1;if(check(mid)) l = mid;else r = mid-1;}cout << r;
}
实数二分代码
#include <cstdio>
#include <iostream>const int N = 100005;
int cows[N]; double sum[N];int n, m;bool check(double avg) {for (int i = 1; i <= n; i++) {sum[i] = sum[i - 1] + cows[i] - avg;}double minv = 0;for (int i = 0, j = m; j <= n; j++, i++) {minv = std::min(minv, sum[i]);if(sum[j] - minv >= 0) return true;} return false;
}int main() {scanf("%d %d", &n, &m);double l = 0, r = 0;for (int i = 1; i <= n; i++) {scanf("%d", &cows[i]);r = std::max(r, (double)cows[i]);}while(r - l > 1e-5) {double mid = (l + r) / 2;if(check(mid)) l = mid;else r = mid;} printf("%d\n", (int)(r * 1000));return 0;
}
注意
eps别太小