HDOJ 2993 MAX Average Problem(斜率优化经典)

题意:

一个长度为 N 的数列,求大于给定长度 k 的区间的最大平均值。

思路:

1. sum[i] 代表 1~i 数列的元素和,则求区间最大平均值相当于 ave(i, j) = (sum[j] - sum[i-1]) / (j - (i-1));

2. 本题要求大于长度 k 的区间,如果我们要维护以 i + k 为结尾,区间长度大于 k 的最大平均值,则要枚举 0~i 种情况,此时时间复杂度为 O(n * n);

3. 于是可以尝试用单调队列来优化这一情况,队列中存放的是斜率值,并且保证队列中存放的点所构成的图形是下凸的,这样才能保证 i + k 与队列中点的切线斜率最大。

4. 对于进队列可以用 3 中的方法维护,出队列则要考虑切线的情况了,由于斜率都是大于 0 且队列中是下凸的,则每次考虑 i + k 与 deq[s] 的连线是否最优即可。

5.“浅谈数形结合思想在信息学竞赛中的应用”中有一个图,看了一目了然:

                    

#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN = 100010;

int sum[MAXN], deq[MAXN];

inline double slope(int i, int j)
{
    return ((double)(sum[i] - sum[j])) / (i - j);
}

int main()
{
    int N, k;
    while (scanf("%d %d", &N, &k) != EOF)
    {
        sum[0] = 0;
        for (int i = 1; i <= N; ++i)
            scanf("%d", &sum[i]), sum[i] += sum[i-1];

        double ans = 0.0;
        int s = 0, e = -1;

        for (int i = 0; i + k <= N; ++i)
        {
            while (s < e && slope(deq[e], deq[e-1]) >= slope(i, deq[e]))
                --e;

            deq[++e] = i;

            while (s < e && slope(i+k, deq[s]) <= slope(i+k, deq[s+1]))
                ++s;

            ans = max(ans, slope(i+k, deq[s]));
        }
        printf("%.2lf\n", ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kedebug/p/2940053.html