题意
给你n个数和一个数字k,要求所有长度 ≥ k \geq k ≥k的所有连续子序列中,平均值最大的值。
思路
设数组
s
[
i
]
s[i]
s[i]代表序列的前缀和,所求的平均值即为
s
[
i
]
−
s
[
j
]
i
−
j
(
i
−
j
≥
k
)
\frac{s[i]-s[j]}{i-j} (i-j\geq k)
i−js[i]−s[j](i−j≥k)
这个值即是直线
s
[
i
]
=
i
∗
k
+
b
s[i]=i*k+b
s[i]=i∗k+b的斜率。
需要注意要保证单调队列的队首元素即是对于每种情况的最优解。同时维护的是一个下凸壳。
要注意这个题需要快速读入。需要快速读入的板子。
代码
//
// Created by yjq on 2019/9/19.
//
#include <bits/stdc++.h>
//#include <cstdio>
//#include <cstring>
//#include <iostream>
//#include <algorithm>
using namespace std;
#define ll long long
//#define ld long double
//#define ull unsigned long long
//#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
ll n, k;
inline char nc() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
inline bool _read(ll &sum) {
char ch = nc();
if (ch == EOF)
return 0;
sum = 0;
while (!(ch >= '0' && ch <= '9'))ch = nc();
while (ch >= '0' && ch <= '9')sum = sum * 10 + ch - 48, ch = nc();
return sum;
}
const int maxn = 1e5 + 10;
ll a[maxn], s[maxn], q[maxn];
//inline int X(int i, int j) {
// return j - i;
//}
//inline int Y(int i, int j) {
// return s[j] - s[i];
//}
//inline double DP(int i, int j) {
// return (double) (s[i] - s[j]) / (double) (i - j);
//}
int main() {
// __;
while (_read(n) && _read(k)) {
for (int i = 1; i <= n; ++i) {
_read(s[i]);
s[i] += s[i - 1];
}
/* while (cin >> n >> k) {
for (int i = 1; i <= n; ++i) {
cin >> s[i];
s[i] += s[i - 1];
}*/
int l = 0, r = 0;
q[++r] = 0;
double ans = 0;
for (int i = 1; i <= n; ++i) {
int cur = i - k + 1;
while (l + 1 < r && (s[i] - s[q[l + 1]]) * (i - q[l + 2]) <= (i - q[l + 1]) * (s[i] - s[q[l + 2]]))
++l;
if (i < k)continue;
ans = max(ans, (double) (s[i] - s[q[l + 1]]) / (double) (i - q[l + 1]));
while (l + 1 < r &&
(s[q[r]] - s[q[r - 1]]) * (cur - q[r]) >=
(q[r] - q[r - 1]) * (s[cur] - s[q[r]]))
--r;
q[++r] = cur;
}
printf("%.2f\n", ans);
}
return 0;
}