zoukankan      html  css  js  c++  java
  • CF1098D Eels

    Solution

    先考虑不进行操作时,怎么吞噬可以得到最多的危险次数。

    有一个结论是:挑最轻的两条鱼合并,可以使答案最大。

    我们简单证明一下:设鱼这个集合为 (S) ,那么一次操作就是从中取出两个最小的元素 (a)(b) ,并把 (a+b) 插入 (S) 。设某次操作 (a)(b) 操作是不危险的,那么满足 (2aleq b) 。则 (b) 不曾被合并过,不然设 (b=c+d) ,其中 (cleq d) ,则 (dgeq b/2>a) ,那么 (d) 应该是被合并的过的,和我们的结论冲突。

    然后可以发现,对所有元素排序,若一个元素对答案产生贡献,是满足 (w_ileq 2cdotsum_{j<i}w_j) 的。

    也就是只要能维护这个判断就行了——根据 (w_i) 分等级: ([2^0,2^1),[2^1,2^2),[2^2,2^3),cdots,[2^{29},2^{30})) ,然后发现一个等级中如果有多个元素,只有最小的可能不是危险的(这个我不会证qwq),因此维护和即可。

    如果有插入和删除操作直接改变区间和和元素就好了。

    代码

    #include<bits/stdc++.h>
    #define ll long long
    
    using namespace std;
    ll q,ans,sum[40];
    char ch[2];
    multiset<ll> num[40];
    
    int main(){
        scanf("%lld",&q);
        while(q--){
            ll x,i;
            scanf("%s%lld",ch,&x);
            for(i=1;(1<<i)<=x;i++);i--;
            if(ch[0]=='+'){
                sum[i]+=x;
                num[i].insert(x);
            }
            else{
                sum[i]-=x;
                num[i].erase(num[i].find(x));
            }
            ll siz=0,ans=0;
            for(int i=0;i<30;i++){
                if(!num[i].size()) continue;
                ans+=(num[i].size()-((*num[i].begin())>2*siz));
                siz+=sum[i];
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    项目架构工具选择
    idea 引入本地jar包
    java 二维/三维/多维数组
    Windows 远程连接
    SQL SERVER 本地同步数据到远程数据服务器
    利用sp_addlinkedserver实现远程数据库链接
    ORACLE 手动添加时间分区
    ORACLE 时间段
    shiro异常简述
    kvm虚拟机克隆
  • 原文地址:https://www.cnblogs.com/jasony/p/13817583.html
Copyright © 2011-2022 走看看