[CF939E]Maximize!

280 篇文章 1 订阅

题目

传送门 to CF

传送门 to VJ

题意概要
维护一个集合 S S S ,支持两种操作:

  1. 加入一个比已有的元素都大的数字。
  2. 对于所有的 S ′ ( S ′ ⫅ S ) S'(S'\subseteqq S) S(SS) ,求 max ⁡ ( S ′ ) − average ( S ′ ) \max(S')-\text{average}(S') max(S)average(S) 的最大值。

(这里的 average \text{average} average 是求平均数的意思啦; max ⁡ \max max 就不解释了)

数据范围与约定
操作数量为 1 0 5 10^5 105 ,加入的数字 x ∈ [ 1 , 1 0 9 ] x\in[1,10^9] x[1,109]

思路

感谢@weixin_30650859 的博客提供了思路。

由于最大值只有 n n n 个,考虑枚举最大值之后最小化平均数。

枚举太慢了。我们每次都会插入最大的数字,只需要考虑以它作为最大值,更新答案即可。

显然,拉低平均值,应该从最小的数字选起。可以用三分。或者是,利用一种 内在联系

此时,那些用来拉低平均数的“小弟”,只会比上一个最大值多,不会更少。证明略。

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0' or c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c and c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(long long x){
	if(x < 0) putchar('-'), x = -x;
	if(x > 9) writeint(x/10);
	putchar((x%10)^48);
}
# define MB template < class T >
MB void getMax(T &a,const T &b){ if(a < b) a = b; }
MB void getMin(T &a,const T &b){ if(b < a) a = b; }

const int MaxN = 500005;
long long s[MaxN];

int main(){
	double average = 1e10, ans = 0;
	for(int T=readint(),i=0,bro=0; T; --T){
		int opt = readint();
		if(opt == 2)
			printf("%.10f\n",ans);
		else{
			s[++ i] = readint(), average = (s[bro]+s[i])/(bro+1.0);
			while(bro+1 < i and (s[bro+1]+s[i])/(bro+2.0) < average)
				++ bro, average = (s[bro]+s[i])/(bro+1.0);
			getMax(ans,s[i]-average);
			s[i] += s[i-1]; // 前缀和
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值