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;
}
-------------------------------------------------------
kedebug
Department of Computer Science and Engineering,
Shanghai Jiao Tong University
E-mail: kedebug0@gmail.com
GitHub: http://github.com/kedebug
-------------------------------------------------------