J Average
我们把矩阵均值用 a i a_i ai 和 b i b_i bi 表示然后去化简发现就是分别求 a a a 序列和 b b b 序列的区间最大均值。
那么现在我们就想求一个序列的区间最大均值。
我们用二分去解决这个问题,我们去 c h e c k check check 能否有区间达到均值 C C C
那么也就是存在: ( a l + a l + 1 + . . . . + a r − 1 + a r ) / L ≥ C (a_l+a_{l+1}+....+a_{r-1}+a_r)/L≥C (al+al+1+....+ar−1+ar)/L≥C
即存在: a l + a l + 1 + . . . . + a r − 1 + a r − L × C ≥ 0 a_l+a_{l+1}+....+a_{r-1}+a_r-L×C≥0 al+al+1+....+ar−1+ar−L×C≥0
即存在: ( a l − C ) + ( a l + 1 − C ) + . . . . + ( a r − 1 − C ) + ( a r − C ) ≥ 0 (a_l-C)+(a_{l+1}-C)+....+(a_{r-1}-C)+(a_r-C)≥0 (al−C)+(al+1−C)+....+(ar−1−C)+(ar−C)≥0
那么我们令 t i = a i − C t_i=a_i-C ti=ai−C
即存在: t l + t l + 1 + . . . . + t r − 1 + t r ≥ 0 t_l+t_{l+1}+....+t_{r-1}+t_r≥0 tl+tl+1+....+tr−1+tr≥0
那么现在令 s u m i sum_i sumi 为 t i t_i ti 的前缀和
即存在: s u m r − s u m l − 1 ≥ 0 sum_r-sum_{l-1}≥0 sumr−suml−1≥0
那么我们只要从左往右遍历右端点,并维护最小的左端点,维护最小的左端点是 O ( 1 ) O(1) O(1) 的,因为我们从左往右遍历右端点的话,新加入的左端点只有一个,这一题还有限制长度,那么我们直接从限制长度开始遍历右端点即可。详情可见代码。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const double eps = 1e-8;
int n, m, x, y, a[N], b[N];
double sum[N];
bool check(double mid, int a[], int n, int lim) {
for (int i = 1; i <= n; ++i) {
sum[i] = sum[i - 1] + a[i] - mid;
}
double mn = 0;
for (int i = lim; i <= n; ++i) {
if (sum[i] - mn > 0 || fabs(sum[i] - mn) < eps) return true;
mn = min(mn, sum[i - lim + 1]);
}
return false;
}
double f(int a[], int n, int lim) {
double l = 0, r = 2e5;
while(r - l > eps) {
double mid = (l + r) / 2;
if (check(mid, a, n, lim)) l = mid;
else r = mid;
}
return l;
}
int main() {
scanf("%d%d%d%d", &n, &m, &x, &y);
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = 1; i <= m; ++i) {
scanf("%d", &b[i]);
}
printf("%.8f", f(a, n, x) + f(b, m, y));
}