Maximize! CodeForces - 939E (三分)

Maximize!

 题目链接:CodeForces - 939E 

题意:不断向集合中插入一个数,且这个数比集合中所有数都大,然后在集合中找一个子集,使得找到的子集中的最大值减去子集的平均值的差最大;

思路:如何选取子集?最后插入的这个数是一定要选的,然后再选小的数,就是一个最大数加上几个用来拉低平均值的小数构成了所需子集;小数一定是从最小值开始连续增加使平均值减小,直到达到一个临界点,再增加自小数平均值就开始增大了,二次函数;

就像班级里拖后腿的学生越多,班级平均成绩越低,因为拖后腿的对平均值不仅没有贡献还降低平均分,当找到某数时,他比平均分大了,就开始为平均分做贡献了;就是三分找这样的位置;

#include <bits/stdc++.h>
using namespace std;
long long a[500010], sum[500010];
int cnt;
double cal(int x){
	return a[cnt]*1.0-(sum[x]+a[cnt])*1.0/((x+1)*1.0);
}
int main(){
	int Q;
	scanf("%d", &Q);
	cnt=0;
	int op;
	sum[0]=0;
	while(Q--){
		scanf("%d", &op);
		if(op==1){
			scanf("%lld", &a[++cnt]);
			sum[cnt]=sum[cnt-1]+a[cnt];
		}
		else{
			int l=1, r=cnt-1;
			if(cnt==1) printf("%.10f\n", 0.0);
			else if(cnt==2)printf("%.10f\n", a[2]*1.0-(a[1]+a[2])*1.0/2.0);
			else{
				int x=1; 
				while(l<r){
					int mid=(l+r)/2;
				 	int midd=(mid+r)/2;
					if(cal(mid)<=cal(midd)){
						x=mid;
						l=mid+1;
					}	
					else{
						x=midd;
						r=midd-1;
					}
				}
				if(x>1&&x<cnt-1)
					printf("%.10f\n", max(max(cal(x), cal(x+1)), cal(x-1)));
				else if(x==1)
					printf("%.10f\n", max(cal(x), cal(x+1)));
				else
					printf("%.10f\n", max(cal(x), cal(x-1)));
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/81122645
今日推荐