BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列
题意:
分析:
拆成链,二分答案,奇偶两个单调队列维护最大子段和,记录方案。
代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define N 200050 #define LL long long #define du double int n, L, R,a[N]; int Q1[N], l1, r1, Q2[N], l2, r2; du s[N], f[N], b[N]; LL gcd(LL x,LL y){ return y?gcd(y,x%y):x; } LL sum[N], mxsum, cnt; bool check(du x){ int i; for(i = 1;i <= 2 * n; i++){ b[i] = 1.0 * a[i] - x; s[i] = s[i - 1] + b[i]; } l1 = r1 = l2 = r2 = 0; Q1[0] = Q2[0] = 0; if(s[L] >= 0) { mxsum = sum[L] ; cnt = L ; return 1; } for(i = L;i <= 2 * n; i++){ if(i & 1){ while(l1 < r1 && i - Q1[l1] > R) l1++; f[i] = s[i] - s[Q1[l1]]; if(f[i] >= 0) { mxsum = sum[i] - sum[Q1[l1]] ; cnt = i - Q1[l1] ; return 1; } while(l2 < r2 && s[i - L + 1] <= s[Q2[r2 - 1]]) r2--; Q2[r2++] = i - L + 1; }else{ while(l2 < r2 && i - Q2[l2] > R) l2++; f[i] = s[i] - s[Q2[l2]]; if(f[i] >= 0) { mxsum = sum[i] - sum[Q2[l2]] ; cnt = i - Q2[l2] ; return 1; } while(l1 < r1 && s[i - L + 1] <= s[Q1[r1 - 1]]) r1--; Q1[r1++] = i - L + 1; } } return 0; } int main(){ scanf("%d%d%d", &n, &L, &R); L = (L + 1) /2 *2; R = R /2 *2; int i; for(i = 1;i <= n; i++){ scanf("%d", &a[i]); a[i + n] = a[i]; sum[i] = sum[i - 1] + a[i]; } for(i = n + 1;i <= n + n; i++){ sum[i] = sum[i - 1] + a[i]; } du l_ = 0, r_ = 1e9; for(i = 1;i <= 40; i++){ du mid = (l_ + r_) / 2; if(check(mid)) l_ = mid; else r_ = mid; } if(mxsum % cnt ==0){ printf("%lld\n", mxsum / cnt); }else{ LL p = gcd(mxsum, cnt); printf("%lld/%lld\n", mxsum / p, cnt / p); } }