奥赛一本通 1434 Best Cow Fences

1434 Best Cow Fences

题目大意

给定一个整数序列 $\{a_n\}$,求长度不小于 $L$ 的子段的最大平均值(一本通题面描述为子序列有误,补充数据范围 $0 \le a_i \le 2000$)。

知识要点

二分、前缀和、斜率、单调队列

解题思路 1

二分枚举平均值 $v$,那么需要找到平均值不小于 $v$ 的子段。如果令 $b_i = a_i - v$,相当于在序列 $\{b_n\}$ 中找总和不小于零的子段,计算它的前缀和 $\{s_n\}$,即要求 $s_r - s_l \ge 0$。枚举区间右端点 $r$, 找到 $0 \le l \le r-L$ 范围内 $s_l$ 的最小值即可。

参考代码 1

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
int n, L, a[N];
long long s[N];

bool check(int v) {
    for(int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i] - v;
    long long sl = 0; //维护前缀最小值
    for(int r = L; r <= n;r++) {
        sl = min(sl, s[r - L]);
        if(s[r] >= sl) return 1;
    }
    return 0;

}
int main() {
    scanf("%d%d", &n, &L);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]), a[i] *= 1000; //直接放大 1000 倍避免浮点数

    int l = 0, r = 2e6;
    while(l < r) {
        int v = (l + r + 1) / 2;
        if(check(v)) l = v;
        else r = v - 1;
    }
    printf("%d\n", l);
    return 0;
}

解题思路 2

显然前缀和序列 $\{s_n\}$ 是单调递增的,而平均值可以写作斜率的形式,考虑使用单调队列求解斜率的最大值。对于枚举的每个右端点 $r$,将对应范围内的左端点保留在队列中,关键在于如何找到斜率的最大值。

A B C

对于从左到右的三个点 $A, B, C$,如果斜率递减的话,那么在计算 $C$ 右边某个点产生的斜率最大值时就不可能选择 $B$,也就是单调队列中只需要保留让斜率递增的点,相当于构成了一个下凸壳。

A B C D E

假如某时刻单调队列中包含三个点 $A, B, C$,计算 $D$ 对应的斜率最大值时选择了 $C$,计算 $E$ 对应的斜率最大值时选择了 $B$。如果要确定单调队列中哪个点才是当前需要的斜率最大值,可以使用二分法。不过根据凸壳的性质可知,最优点在左侧的斜率肯定小于最优点在右侧的斜率,从得到全局最优的角度来看,单调队列中只需要保留当前最优点及其右侧的点,这样时间复杂度优化为 $O(n)$。

参考代码 2

#include <bits/stdc++.h>
using namespace std;

const int N = 100005;
int Q[N], l = 1, r = 0; //单调队列
long long ans, s[N];
long long slope(int i, int j) {
    return (s[i] - s[j]) / (i - j);
}

int main() {
    int n, L, a;
    scanf("%d%d", &n, &L);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a), s[i] = s[i - 1] + a * 1000;

    for(int i = L; i <= n; i++) {
        while(l < r && slope(Q[r - 1], Q[r]) >= slope(Q[r], i - L)) r--;
        Q[++r] = i - L; //新元素入队

        while(l < r && slope(Q[l], i) <= slope(Q[l + 1], i)) l++; //暴力找最值
        ans = max(ans, slope(Q[l], i));
    }
    printf("%d\n", ans);
    return 0;
}
posted @ 2026-09-07 15:57  萧西待水  阅读(3)  评论(0)    收藏  举报