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

· · 题解

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

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

思路

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

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

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

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

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

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

那怎么办呢?

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

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

res=res+empty_{headempty}

那有 ~~更水的~~ 数据连 3 都不够($us3<tailempty-headempty+1$)就 ~~拆东墙补西墙~~,把区间 i 拆下要减的 1-3 (离 2 最近的)的距离(包括 1 个端点)记为 $wipe_i$(加到 ~~水区间~~ 的 2 边上) 即 $res=res+empty_{headempty}-wipe_{headwipe}

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

排序:

$empty$ 从大到小。 $wipe$ 从小到大。 ($add_{headadd} \geq empty_{headempty}$ 时)先用 $add$。 否则用 $us3$(因为 ~~可以白嫖~~)最后用 $wipe$,即 ~~有代价的白嫖~~($us3$ 没了所以可以用)。 $add_i$ 用了 $wipe_i$ 就用不了了(反过来也一样)用 set 即可解决这个问题。 为使 $add$ 和 $wipe$ 一一对应,$add_k=0$ 时也应算入。 记得把 $wipe$ 生成的 $empty$ 重新加入。 ------------ # 代码 ------------ ```cpp #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; } ``` ------------ # 总结 ------------ ~~洛谷月赛真是越来越毒瘤了~~ ~~都开始传播白嫖主义了~~