1 条题解

  • 0
    @ 2025-8-24 22:33:41

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Perfound
    死在了起跑线,死人一生平安

    搬运于2025-08-24 22:33:41,当前版本为作者最后更新于2021-09-12 10:13:04,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P7855 「EZEC-9」 暂颓恒卷 题解

    为防棕名先发个声明:和 wyy332623 的 3 个代码雷同是因为我一天内交的次数满了,就把代码给他交.


    思路


    这题最重要的一点是要知道 1-3 之间(无 2 或 1)可全部变卷。

    方便起见,把每个 1-2(之间无 2 或 1)叫做一个区间。

    要求最大值,那就先把所有输入的区间内 1-3(离 2 最近的)的距离(包括 2 个端点)之和记作 resres

    那这 1-3(离 2 最近的)之间的3就没用了,数量记作 us3us3(不包括 2 个端点)。

    要移动 3(离 2 最近的)当然要移到那个 2(本区间)边上,区间 i 的移动所加的值记为 addiadd_ i

    但这通过率不到 2% 的 大水题 肯定会有像 1-2(无 1 或 2)之间只有 4 的 比较水的 数据,把它定义为 水区间

    那怎么办呢?

    肯定先用 us3us3 因为它可以进行 人见人爱花见花开的白嫖,把它放到 水区间 的 2 边上。

    水区间 i 内 4 的个数记为 emptyiempty_i

    res=res+emptyheademptyres=res+empty_{headempty}

    us3=us31us3=us3-1白嫖次数减一)//哭

    那有 更水的 数据连 3 都不够(us3<tailemptyheadempty+1us3<tailempty-headempty+1)就 拆东墙补西墙,把区间 i 拆下要减的 1-3 (离 2 最近的)的距离(包括 1 个端点)记为 wipeiwipe_i(加到 水区间 的 2 边上)

    res=res+emptyheademptywipeheadwiperes=res+empty_{headempty}-wipe_{headwipe}

    emptyheademptywipeheadwipe<0empty_{headempty}-wipe_{headwipe}<0 时退出)因为这样 resres 会倒减且这是最后方案(即 白嫖失败

    排序:

    addadd 从大到小。

    emptyempty 从大到小。

    wipewipe 从小到大。

    addheadaddemptyheademptyadd_{headadd} \geq empty_{headempty} 时)先用 addadd

    否则用 us3us3(因为 可以白嫖)最后用 wipewipe,即 有代价的白嫖us3us3 没了所以可以用)。

    addiadd_i 用了 wipeiwipe_i 就用不了了(反过来也一样)用 set 即可解决这个问题。

    为使 addaddwipewipe 一一对应,addk=0add_k=0 时也应算入。

    记得把 wipewipe 生成的 emptyempty 重新加入。


    代码


    #include<bits/stdc++.h>
    using namespace std;
    int add[2000010],wipe[2000010];
    struct ad{
    	int v,p;
    	friend bool operator <(ad x,ad y){
    		return x.v==y.v?x.p>y.p:x.v>y.v; 
    	}
    };
    struct wp{
    	int v,p;
    	friend bool operator <(wp x,wp y){
    		return x.v==y.v?x.p<y.p:x.v<y.v; 
    	}
    };
    struct ep{
    	int v;
    	friend bool operator <(ep x,ep y){
    		return x.v>y.v; 
    	}
    };
    set<ad>s1;set<wp>s2;
    multiset<ep>s3;
    int empty[2000010],is[2000010];
    bool cme(int a,int b){return a>b;}
    int hw,he,ha;
    int ta=-1,tw=-1,te=-1;
    int f,b13,b3,b1,b2;
    int res,us3;
    void usa(){
    	auto it=s1.begin();
        s2.erase((wp){wipe[(*it).p],(*it).p});
        res+=(*it).v,s1.erase(it);
    }
    void usw(){
    	auto it=s2.begin();
    	s1.erase((ad){add[(*it).p],(*it).p});
        res+=(*s3.begin()).v-(*it).v;
    	s3.erase(s3.begin());
    	s3.insert((ep){is[(*it).p]});
    	s2.erase(it);
    }
    int main(){
        int k,c,a;
        scanf("%d%d",&k,&c);
        for(int i=1;i<=k;i++){
            scanf("%d",&a);
            if(a==1){
                if(b13>0)wipe[++tw]=i-b3,is[tw]=i-b2-1;
                if(b13<=0&&i!=1)empty[++te]=i+b13-1;
                f=min(f+1,2),us3+=(f==2);
                if(b13>=0)res+=i-b13;
                else res++;
                b13=b1=i,f=0;
            }else if(a==2){
                if(b13!=b1)wipe[++tw]=b13-b1,is[tw]=i-b1-1;
                if(f==0&&i!=1)empty[++te]=i-b13-1;
                if(f>0)add[++ta]=i-b13-1;b13=-i,b2=i,f=0;
            }else if(a==3){
                if(b13>0)res+=i-b13,f=min(f+1,2),us3+=(f==2);//去掉二个端点 f 就这样搞 
                else add[++ta]=i+b13-1,b3=i,res++;b13=i;
            }
        }
        for(int i=0;i<=ta;i++)s1.insert((ad){add[i],i});
        for(int i=0;i<=tw;i++)s2.insert((wp){wipe[i],i});
        for(int i=0;i<=te;i++)s3.insert((ep){empty[i]});
        for(int i=0;i<c;i++){
            if(s3.size()){
                if(s1.size()){
                    if((*s1.begin()).v>=(*s3.begin()).v)usa();
                    else if((us3--)>0)res+=(*s3.begin()).v,s3.erase(s3.begin());
                    else if(!s2.size())usa();
                    else if((*s1.begin()).v>=(*s3.begin()).v-(*s2.begin()).v)usa();
                    else if((*s3.begin()).v-(*s2.begin()).v>0)usw();
                    else break;
                }else if((us3--)>0)res+=(*s3.begin()).v,s3.erase(s3.begin());
                else if(!s2.size())break;
                else if((*s3.begin()).v-(*s2.begin()).v>0)usw();
                else break;
            }else if(s1.size())usa();
            else break;
        }
        cout<<res;
        return 0;
    }
    

    总结


    洛谷月赛真是越来越毒瘤了

    都开始传播白嫖主义了

    • 1

    信息

    ID
    6780
    时间
    1000~2000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者