[Solution] ABC341G
Description
长度 \(n\) 的数列 \(A=(A_1,A_2,\ldots,A_n)\)。
对于每个 \(k\) \((1\le k\le n)\),选择满足 \(k\le r\le n\) 的整数 \(r\),使得 \(A\) 序列第 \(k\) 项到第 \(r\) 项的平均值的最大。
Solution
设 \(s_i\) 为 \(a_i\) 的前缀和,\(f_i\) 为 \(i\) 位置的答案。
\[f_{i+1}=\max_{j=i+1}^n \dfrac{s_j-s_i}{j-i}
\]
即点 \((i,s_i)\) 和点 \((j,s_j)\) 所在直线斜率的最大值。
倒序枚举,使用单调栈维护上凸壳即可。
Code
#include <cstdio>
#define int long long
using namespace std;
const int N = 200005;
int n, top, a[N], s[N]; double f[N];
double slope(int x, int y) {return 1.0 * (a[x] - a[y]) / (x - y);}
signed main()
{
scanf("%lld", &n);
for(int i = 1; i <= n; ++ i)
scanf("%lld", &a[i]), a[i] += a[i - 1];
s[++top] = n;
for(int i = n - 1; i >= 0; -- i)
{
while(top > 1 && slope(s[top - 1], i) < slope(s[top - 1], s[top])) -- top;
f[i + 1] = slope(s[top], i);
s[++top] = i;
}
for(int i = 1; i <= n; ++ i) printf("%.8lf\n", f[i]);
return 0;
}