1. 程式人生 > >BZOJ_3316_JC loves Mkk_ 二分答案 + 單調隊列

BZOJ_3316_JC loves Mkk_ 二分答案 + 單調隊列

else ostream 最大 height check turn main ble AI

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

BZOJ_3316_JC loves Mkk_ 二分答案 + 單調隊列