开始还以为是尺取。发现行不通。
一看标签二分答案,恍然大悟。 二分一个\(mid\)(实数),把数列里每个数减去\(mid\),然后求前缀和,在用单调队列维护\(sum[i-t\text{~}i-s]\)的最小值,用\(sum[i]\)减去它,如果大于等于\(0\)就说明\(mid\)可行。#include#include using namespace std;#define INF 2147483647const int MAXN = 100010;const double eps = 1e-6;int n, s, t, head, tail;int a[MAXN];int q[MAXN];inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-')w = -1;ch = getchar();} while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0',ch = getchar(); return s * w;}int Min = INF, Max = -INF;double l, r, mid, sum[MAXN];inline int check(double mid){ head = tail = 0; for(int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i] - mid; for(int i = s; i <= n; ++i){ int in = i - s; while(head < tail && sum[in] < sum[q[tail]]) --tail; q[++tail] = in; while(head < tail && q[head + 1] < i - t) ++head; if(sum[i] - sum[q[head + 1]] >= 0) return 1; } return 0;}int main(){ n = read(); s = read(); t = read(); for(int i = 1; i <= n; ++i){ a[i] = read(); Min = min(Min, a[i]); Max = max(Max, a[i]); } l = Min; r = Max; while(r - l > eps){ mid = (l + r) / 2.0; if(check(mid)) l = mid; else r = mid; } printf("%.3lf\n", l); return 0;}