原题链接
集合操作
题目性质
假设从S中的一个答案子集s={x1,x3,⋯,xn−1,xm},其中xm为最大值,长度为n
注意这个n,m和题目中的并不相同,这里但指集合s的属性
- 一个集合s的答案值max(s)−mean(s)为
res=xm−nx1+x2+⋯+xn−1+xm=nxm−x1+nxm−x2+⋯+nxm−xn−1
-
每次选出的集合s要包含新加入的元素xM
xm是当前集合上一个的最大值
答案集合s={x1,x3,⋯,xn−1,xm},则将xM去替换xm我们可以知道
新的集合s1={x1,x3,⋯,xn−1,xM}的res一定不会比s的res要小
可以带入上面的公式试一试哦
-
我们选择的集合s一定是从从S中选择最小的n−1个元素加上最大的一个元素xm构成
通过res表达式可知当我们确定选n个元素时候选最小的n−1个元素且xm选最大的那个元素一定比选择其他元素得到的大
或者 我们需要平均值最小 那么选的数肯定也是最小的
-
添加元素
我们发现我们需要的子集一定是从第一个元素开始的有序子集,需要从小到大依次的添加一个数,但是加到哪一个位置就不能加了呢?
假设一个集合s1={x1,x3,⋯,xn−1,xm}我们尝试加入xn使s2={x1,x3,⋯,xn−1,xn,xm}
ress1=nxm−x1+nxm−x2+⋯+nxm−xn−1
ress2=n+1xm−x1+n+1xm−x2+⋯+n+1xm−xn−1+n+1xm−xn
当我们发现ress1−ress2<0的时候我们就可以加入xn,即:
(nxm−x1−n+1xm−x1)+(nxm−x2−n+1xm−x2)+⋯+(nxm−xn−1−n+1xm−xn−1)<n+1xm−xn
进一步化简话
n(n+1)xm−x1+n(n+1)xm−x2+⋯+n(n+1)xm−xn−1<nxm−xn
n+1xm−x1+n+1xm−x2+⋯+n+1xm−xn−1<xm−xn
nxm−sum(x1,x2,⋯,xn)<(n+1)(xm−xn)
xm+sum(x1,x2,⋯,xn−1)>(n+1)xn
所以说当我们需要添加的元素满足xm+sum(x1,x2,⋯,xn−1)>(n+1)xn则该元素就可以将xn添加进来
-
删除元素
根据上面四条我们可以确定我们需要的元素是从小到大列举的 如果想删除某一个元素 肯定是删除最后添加的元素(不是最大值),但是我们在进行第四步的时候可以不把这个元素添加进来呀,添加进来的就是最优的情况,所以我们不需要删除元素,只判断哪一个元素是否可以添加就行了
实际代码
a[N]
记录读入的数字 ,s
记录前n个元素和,k
当前集合中已经加入到哪个位置上了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #include<iostream> using namespace std; const int N=5e5+5; int q,x,a[N],k,n; double s; int main(){ scanf("%d",&q); while(q--){ scanf("%d",&x); if(x==1)scanf("%d",&a[++n]); else{ while(k+1<=n&&a[k+1]<(s+a[n])/(k+1))s+=a[++k]; printf("%0.6f\n",a[n]-(a[n]+s)/(k+1)); } } return 0; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include<iostream> using namespace std; const int N=5e5+5; int q,x,a[N],k,n; double s; int main(){ scanf("%d",&q); while(q--){ scanf("%d",&x); if(x==1){ scanf("%d",&a[++n]); while(k+1<=n&&a[k+1]<(s+a[n])/(k+1))s+=a[++k]; }else printf("%0.6f\n",a[n]-(a[n]+s)/(k+1)); } return 0; }
|
发个牢骚
第一次打周赛,迟到了五分种,以至于这道题就差最后三分钟可以提交,不过幸好的是一遍AC没有改错哈哈哈
第 62 场周赛 - AcWing