极值分析 (extreme) 题解

极值分析 (extreme) 题解

题意

给定长度为 \(n\) 的正整数序列 \(a_1, a_2, \cdots, a_n (a_i \le 10 ^ 8)\) 以及正整数 \(k, L, R\),求出

\[E = \max \left ( \frac{\max_{i, j \in [l, r]} (a_i - a_j) }{r - l + k} \right ) (1 \le l \le r \le n, L \le r - l + 1 \le 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\) 最优,则有

\[E_{\max} \ge \frac{\max_{i, j \in [l, l + L - 1]} (a_i - a_j)}{L - 1 + k} \]

则依次枚举 \(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();
}
posted @ 2023-02-26 00:00  JerryTcl  阅读(69)  评论(0)    收藏  举报