显然,高度小于 \(h_1\) 的要舍去。剩下的排序。
猜每次与 \(1\) 合并的都是连续的一段。这样就可以列出方程
\[dp_{k, i} = \max\{\frac{dp_{k - 1, j} + s_i - s_j} {i - j + 1}\} \]
发现可以维护一个凸包。
#include <cstdio>
#include <iostream>
#include <algorithm>
//decimal lib included
const int MAXN = 8e3 + 19;
int n, k, p;
int h[MAXN], cnt, s[MAXN];
double dp[MAXN][MAXN];
std::pair<int, int> pre[MAXN][MAXN];
int q[MAXN], head, tail;
int u, v;
Decimal dfs(int a, int b){
if(a == 0)
return Decimal(h[1]);
return (dfs(pre[a][b].first, pre[a][b].second) + s[b] - s[pre[a][b].second]) / (b - pre[a][b].second + 1);
}
int main(){
std::scanf("%d%d%d", &n, &k, &p);
std::scanf("%d", h + ++cnt);
for(int i = 2; i <= n; ++i){
std::scanf("%d", h + ++cnt);
if(h[cnt] <= h[1])
--cnt;
}
std::sort(h + 1, h + 1 + cnt);
for(int i = 1; i <= cnt; ++i)
s[i] = s[i - 1] + h[i];
int lim = std::min(k, n - 1);
for(int i = 1; i <= cnt; ++i)
dp[0][i] = h[1];
for(int b = 1; b <= lim; ++b){
dp[b][1] = h[1]; q[head = tail = 0] = 1;
for(int i = 2; i <= cnt; ++i){
dp[b][i] = dp[b][i - 1], pre[b][i] = pre[b][i - 1];
while(
head < tail &&
(dp[b - 1][q[head + 1]] + s[i] - s[q[head + 1]]) / (i - q[head + 1] + 1) >=
(dp[b - 1][q[head]] + s[i] - s[q[head]]) / (i - q[head] + 1)
)
++head;
double res = (dp[b - 1][q[head]] + s[i] - s[q[head]]) / (i - q[head] + 1);
if(res > dp[b][i])
dp[b][i] = res, pre[b][i] = std::make_pair(b - 1, q[head]);
while(
head < tail &&
(s[q[tail]] - dp[b - 1][q[tail]] - s[q[tail - 1]] + dp[b - 1][q[tail - 1]]) / (q[tail] - q[tail - 1]) >=
(s[i] - dp[b - 1][i] - s[q[tail - 1]] + dp[b - 1][q[tail - 1]]) / (i - q[tail - 1])
)
--tail;
q[++tail] = i;
}
if(dp[b][cnt] >= dp[u][v])
u = b, v = cnt;
}
std::cout << dfs(u, v).to_string(p + 1)) << std::endl;
return 0;
}