传送门:http://codeforces.com/problemset/problem/939/E
题意:
有两种操作:
(1)在集合S中插入一个元素
(2)输出最大的 Max(s)−mean(s) M a x ( s ) − m e a n ( s ) ——其中s是集合的子集,Max(s)表示s中最大的元素,mean(s)表示s的平均值
(3) 输入保证插入的元素比原集合中的所有元素都要大
分析:
(1)有一个前提条件:所选的最优的集合s必然包含集合S中最大的元素,其他元素必然是S的一个前缀
(2)函数 Max(s)−mean(s) M a x ( s ) − m e a n ( s ) 有极值
(3)对于有极值的函数考虑用二分或者三分的思路求解
题解(二分思路):
设
mi=an−an+∑i−1j=0aji+1 m i = a n − a n + ∑ j = 0 i − 1 a j i + 1得 mi+1−mi m i + 1 − m i = an+∑i−1j=0aj−ai(i+1) a n + ∑ j = 0 i − 1 a j − a i ( i + 1 ) (此处去除了分母,因为分母对于函数的正负号没有影响,而二分过程只与函数的正负号有关,故可以去除分母)
设 f(i)=mi+1−mi f ( i ) = m i + 1 − m i
可以用前一项减去后一项来证明证明 f(i) f ( i ) 是非递减的
二分找到最小的 i i 使得 时 Max(s)−mean(s) M a x ( s ) − m e a n ( s ) 取得最大值
代码:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
long long sum[500005];
long long a[500005];
int main()
{
int q;
cin>>q;
int cnt=0;
memset(a,0,sizeof a);
memset(sum,0,sizeof sum);
double ans=0;
while(q--)
{
int op;
cin>>op;
if(op==1)
{
cin>>a[cnt];
int l=0,r=cnt;
if(cnt>=1)
sum[cnt]=sum[cnt-1]+a[cnt];
else
sum[cnt]=a[cnt];
while(l<r)
{
int mid=(l+r)/2;
long long fi;
if(mid!=0)
fi=a[cnt]+sum[mid-1]-a[mid]*(mid+1);
else
fi=a[cnt]-a[mid]*(mid+1);
if(fi<=0) r=mid;
else l=mid+1;
}
double avg=1.0*(sum[r-1]+a[cnt])/(r+1);
double tmp=a[cnt]-avg;
ans=max(ans,tmp);
cnt++;
}else{
printf("%.10f\n",ans);
}
}
return 0;
}