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);
}
}