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.“浅谈数形结合思想在信息学竞赛中的应用”中有一个图,看了一目了然:

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

 

#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;

}

你可能感兴趣的:(max)