codeforces-939E Maximize!

题意
维护一个集合,两种操作:
1、向集合加入一个数,保证这个数比集合中所有数都大
2、在集合中找一个子集,使子集中最大值减平均值最大,输出这个最大值
解题思路
加入第 i i i个数 A i Ai Ai后,考虑包含 A i Ai Ai的子集对 a n s ans ans的影响。
因为所选子集中最大值已经确定为 A i Ai Ai,只需尽可能减小子集中的平均值。
由贪心的思想,一定尽可能选较小的数,即选取的一定为序列 A A A的一个前缀,于是暴力方法就是枚举前缀结束位置 j j j
由平均数性质,向后枚举时如果新加入的 A j Aj Aj小于之前已经加入的数的平均值,则一定拉低平均值,反之会抬高平均值。
由于 A A A递增,显然所得平均值是单峰的,这样就可以使用三分。
代码

#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
using namespace std;
long long sum[500005];
double ans;
int q,x,num;
inline double check(int w){
	return 1.0*(sum[w]+x)/(w+1);
}
int main(){
	int opt;
	scanf("%d",&q);
while(q--){
	scanf("%d",&opt);
	if(opt==2) {printf("%.8lf\n",ans);continue;}
	scanf("%d",&x);
	int l=1,r=num;
	while(l<r){
		int mid=l+r>>1;
		int midd=mid+r>>1;
		if(mid==midd) midd++;
		double r1=check(mid),r2=check(midd);
		if(r1>r2) l=mid+1;
		else r=midd-1;
	}
	if(l==r) ans=max(ans,1.0*x-1.0*(sum[l]+x)/(l+1));
	sum[++num]=x;sum[num]+=sum[num-1];
}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值