模板:单调队列DP求在区间([l,r]) 中长度至少为 (m) 的最大平均值
题目链接:Here
题意
给定一个长度为 (n) 的序列 (a_1) ~ (a_n) ,从中选取一段长度在 (s) 到 (t) 之间的连续一段使其平均值最大。((n<=100000))
分析
二分答案平均值。
在 (a[i]-mid) 中找到一段合法的串使其权值和最大。
当最大权值和大于等于 (0) 时则 (mid) 上移。
求最大权值和用单调队列就行。(预处理 (a[i]-mid) 的前缀和 (sum[i]) )
Show Code
const int N = 1e5 + 10; int n, s, t; double a[N], sum[N]; int q[N]; bool check(double x) { for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + (a[i] - x); sum[0] = 0; int hh = 1, tt = 0; memset(q, 0, sizeof(q)); for (int i = s; i <= n; ++i) { while (hh <= tt and sum[q[tt]] > sum[i - s]) tt--; q[++tt] = i - s; while (hh <= tt and q[hh] < i - t) ++hh; if (hh <= tt and sum[i] - sum[q[hh]] >= 0) return true; } return false; } int main() { cin.tie(nullptr)->sync_with_stdio(false); cin >> n >> s >> t; for (int i = 1; i <= n; ++i) cin >> a[i]; double l = -10000, r = 10000; while (r - l > 1e-5) { double mid = (l + r) / 2.0; if (check(mid)) l = mid; else r = mid; } cout << fixed << setprecision(3) << l; }