记录编号 280605 评测结果 AAAAAAAAAA
题目名称 [HZOI 2016]最佳序列 最终得分 100
用户昵称 Gravatarkito 是否通过 通过
代码语言 C++ 运行时间 0.052 s
提交时间 2016-07-10 16:37:25 内存使用 4.13 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
/*
	二分答案。
		我们的二分范围是[0,maxn],其中maxn是数列A中的最大值。
		每次去mid,我们可以用原数列的每一项都减去mid,得到一个新的数列,这个数列中可能有正
	有负,我只需要求在新数列中某一个长度在[L,R]之间的序列之和大于零,证明我的mid取小了,
	反之如果所有满足条件的区间之和都小于零,证明mid取大了。
		至于求和我们可以使用前缀和。用单调队列维护符合情况的左边界来优化。
		具体不详细说了,自己看吧。 
*/
int fate,lucy,windy;
double alice[200010]={0};
double maxn=-1.0;
inline double rider(double a){
	if(a>0)	return a;
	else	return -a;
}
struct ss{
	double nazi;
	int id;
}Tina[200010];

deque<ss> asuna;
double archer(int a,int k){
	while(!asuna.empty()&&asuna.back().nazi>=Tina[a].nazi)	asuna.pop_back();
	asuna.push_back(Tina[a]);
	while(!asuna.empty()&&asuna.front().id<k)	asuna.pop_front();
	return asuna.front().nazi;
}

int main(){
	freopen("bestseq.in","r",stdin);
	freopen("bestseq.out","w",stdout);
	scanf("%d%d%d",&fate,&lucy,&windy);
	int ax;
	for(int i=1;i<=fate;++i){
		scanf("%d",&ax);
		alice[i]=(double)ax;
		//scanf("%lf",&alice[i]);
		if(alice[i]>maxn)	maxn=alice[i];
		//printf("%.4lf ",alice[i]);
		Tina[i].id=i;
	}
	double l=0,r=(double)maxn,mid,q;
	int j;
	bool Luka;
	while(rider(r-l)>1e-7){
		Luka=false;
		mid=(r+l)/2;
	//	printf("\n\n\n%.4lf %.4lf %.4lf\n",l,r,mid);
		while(!asuna.empty())	asuna.pop_front();
		for(int i=1;i<=fate;++i){
			Tina[i].nazi=((double)alice[i])-mid;
	//		printf("%.4lf ",Tina[i].nazi);
			Tina[i].nazi+=Tina[i-1].nazi;
		}
	//	printf("\n");
		for(int i=1;i<=fate;++i){
		//	printf("%d ",alice[i]);
		}
	//	printf("\n");
		for(int i=lucy;i<=fate;++i){
			j=i-lucy;
			q=Tina[i].nazi - archer(j,i-windy);
	//\		printf("%d %.4lf\n",i,q);
			if(q>1e-7){
				Luka=true;
				break;
			}
		}
		if(Luka)	l=mid+1e-7;
		else	r=mid-(1e-7);
	}
	printf("%.4lf",mid);
	return 0;
}