【洛谷 P1419】 尋找段落(二分答案,單調佇列)
阿新 • • 發佈:2018-12-30
開始還以為是尺取。發現行不通。
一看標籤二分答案,恍然大悟。
二分一個\(mid\)(實數),把數列裡每個數減去\(mid\),然後求字首和,在用單調佇列維護\(sum[i-t\text{~}i-s]\)的最小值,用\(sum[i]\)減去它,如果大於等於\(0\)就說明\(mid\)可行。
#include <cstdio> #include <algorithm> using namespace std; #define INF 2147483647 const 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; }