极值分析 (extreme) 题解
极值分析 (extreme) 题解
题意
给定长度为 \(n\) 的正整数序列 \(a_1, a_2, \cdots, a_n (a_i \le 10 ^ 8)\) 以及正整数 \(k, L, R\),求出
解答
显然当 \(k\) 单调增加时,\(E\) 单调减少,考虑二分
原式即 \(\displaystyle k = \frac{\max_{i, j \in [l, r]} (a_i - a_j) + El - Er}{E}\)
若 \(|i - j| + 1 \ge L\)
若 \(i < j\),则显然取 \(l' = i \ge l, r' = j \le r\) 时,\(El' - Er' \ge El - Er\) 最优
所以有 \(\displaystyle k_{\max} \ge \frac{\max \left( (a_i + Ei) - (a_j + Ej) \right)}{E}\)
其中 \(L \le j - i + 1 \le R\)
可以依次枚举 \(i\),用优先队列维护区间 \([i + L - 1, i + R - 1]\) 中 \(a_j + Ej\) 的最小值计算
同理,若 \(i > j\),则显然取 \(l' = j, r' = i\) 最优
所以有 \(\displaystyle k_{\max} \ge \frac{\max \left( (a_i - Ei) - (a_j - Ej) \right)}{E}\)
则依次枚举 \(i\),用优先队列维护区间 \([i - L + 1, i - R + 1]\) 中 \(a_j - Ej\) 的最小值计算
当 \(|i - j| + 1 \le L\) 时,取 \(r - l + 1 = L\) 最优,则有
则依次枚举 \(i\),用优先队列维护区间 \([i - L + 1, i + L - 1]\) 中 \(a_j\) 的最小值计算
实现中,
可将 \(|i - j| + 1 \le L\) 时算出的 \(E_{\max} \ge x\) 当做二分的左端点,再二分 \(E\) 计算 \(|i - j| + 1 \ge L\) 时的 \(E_{\max}\ge y\) 求出答案
也可直接二分 \(E\) 计算 \(k\) 求出 \(E_{\max} \ge y\),再与 \(|i- j| + 1 \le L\) 时算出的 \(E_{\max} \ge x\) 取 \(\max\)
实现
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
int t, n, k, L, R;
int a[100010];
struct FindMin {
pair<int, double> Q[100010];
int h, t, len, nw;
void Init(int l) { h = 0, t = -1, len = l; nw = 0; }
void Rshift() { if(h <= t && Q[h].fi == ++nw - len) ++h; }
void Push(double x) {
while(t >= h && Q[t].se >= x) --t;
Rshift(), Q[++t].fi = nw, Q[t].se = x;
}
double Get() { return Q[h].se; }
} qwq;
int Check(double e) {
double ans = -1e18;
qwq.Init(R - L + 1);
for(int i = L; i < R; ++i) qwq.Push(a[i] + e * i);
for(int i = 1; i <= n - R + 1; ++i)
qwq.Push(a[i + R - 1] + e * (i + R - 1)),
ans = max(ans, a[i] + e * i - qwq.Get());
for(int i = n - R + 2; i <= n - L + 1; ++i)
qwq.Rshift(), ans = max(ans, a[i] + e * i - qwq.Get());
qwq.Init(R - L + 1);
for(int i = L; i <= n; ++i)
qwq.Push(a[i - L + 1] - e * (i - L + 1)),
ans = max(ans, a[i] - e * i - qwq.Get());
return ans > e * k;
}
double GetL() {
double ans = -1e18;
qwq.Init(L * 2 - 1);
for(int i = 1; i <= L - 1; ++i) qwq.Push(a[i]);
for(int i = 1; i <= n - L + 1; ++i)
qwq.Push(a[i + L - 1]), ans = max(ans, a[i] - qwq.Get());
for(int i = n - L + 2; i <= n; ++i)
qwq.Rshift(), ans = max(ans, a[i] - qwq.Get());
return ans / (L + k - 1);
}
void Solve() {
scanf("%d %d %d %d", &n, &k, &L, &R);
for(int i = 1; i <= n; ++i) scanf("%d", a + i);
double L = GetL(), R = 1e8, M;
for(int i = 1; i <= 50; ++i)
(Check(M = (L + R) / 2) ? L : R) = M;
printf("%.4lf\n", M);
}
int main() {
freopen("extreme.in", "r", stdin);
freopen("extreme.out", "w", stdout);
for(scanf("%d", &t); t--; ) Solve();
}

浙公网安备 33010602011771号