集合操作(双指针,贪心)

题意

给定一个由正整数(最初为空)组成的多重集S。多重集表示可能存在重复元素的集合。

请你对该集合执行Q次操作,操作分为两种:

  • 增加操作,格式为1 x,将一个正整数x加入到集合S中。数据保证,x不小于当前S中的任何元素。
  • 询问操作,格式为2,找到一个当前S的子集s,要求max(s)mean(s)的值应尽可能大,输出max(s)mean(s)的最大可能值。max(s)表示s中最大元素的值,mean(s)表示s中所有元素的平均值。

题目链接:https://www.acwing.com/problem/content/4505/

数据范围

1Q5×105
1x109

思路

这里给出三条结论,不进行详细证明了(好像也不难证):

  • 集合中的元素一定包含新加入的元素,以及最小的k个元素

  • 最终答案关于k的函数一定是先增后减的

  • 新加入元素之后,最优的k是不减的。

因此,用一个指针指向k,维护使得均值最小的k

详细证明见:https://www.acwing.com/solution/content/128919/

代码

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 500010;

int n;
ll a[N];
int cnt;

int main()
{
    scanf("%d", &n);
    double s = 0;
    int k = 0, op;
    while(n --) {
        scanf("%d", &op);
        if(op == 1) {
            int x;
            scanf("%d", &x);
            cnt ++, a[cnt] = x;
        }
        else {
            while(k + 1 <= cnt && (s + a[cnt]) / (k + 1) > a[k + 1]) {
                k ++;
                s += a[k];
            }
            printf("%.6f\n", a[cnt] - (s + a[cnt]) / (k + 1));
        }
    }
    return 0;
}
posted @   pbc的成长之路  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示