一种更优秀的「EZEC-5」魔法 做法

SSerxhs

2021-01-23 20:22:21

Solution

可以证明,所有的 $1,2$ 操作都会对整个区间进行,并且先做 $1$ 操作后做 $2$ 操作。末处补充证明~~性感理解~~。 考虑 2 操作对 $s$ 的影响,则 $2^ksum\ge s$ 意味着 $sum\ge \frac{s}{2^k}$,这时我们发现 2 操作可以不视为对序列操作而是视为对 $s$ 操作。 2 操作次数显然是可以枚举的,所以题目转化为求最小 1 操作次数。 对于同一长度,同样操作次数加的值是一样的,也就是说同一长度只要保留最大子段和就可以了。 那么可以考虑计算所有不同长度的子段的最大子段和。由于修改只有整体加,那么类似斜率优化可以知道有用的 $(len,s_{len})$ 构成一个凸包。那么可以发现 这玩意不就是[世上最幸福的女孩](https://www.luogu.com.cn/problem/P5073)?? 所以跑个闵科夫斯基和合并凸包,再枚举 2 操作次数即可。 总时间复杂度 $O(n\log n+nloga)$,空间复杂度 $O(n\log n)$,明显会 MLE 那题写线性空间挺烦的,我们可以考虑最终只需要全局最大子段和,不需要保存每一层的凸包,那么滚动数组就好了。 另外根据斜率优化的原理应该可以轻易做到 $O(n\log n+\log a)$,这里不展开。 以下是证明部分 先证明先做 1 后做 2 因为 2 操作是乘法,那么考虑 1 对 2 的贡献可证明。 1 操作对整个区间做十分显然,不叙 关于 2 操作,首先考虑到所有子段进行完 1 操作后与长度没有关系,可以直接选出同样 1 操作次数的最大子段和,由于选取的是最大子段和 $[l,r]$,那么不存在 $i\in [l,r]$ 使得 $\max([l,i],[i,r])>[l,r]$,则若 2 操作对 $[ll,rr]$ 做更优,则观察增量 $[ll,rr]\times 2>[l,r]*2$,分别令 $i=ll,i=rr$ 可推出与上式矛盾。 ```cpp #include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+2,M=4e5+2,K=2; const ll inf=-9e18; struct pt { int x; ll y; pt(int a=0,ll b=inf):x(a),y(b){} bool operator<(register pt o) {return ((ll)x*o.y<(ll)y*o.x)||((ll)x*o.y==(ll)y*o.x)&&(x+y<o.x+o.y);}//顺时针 pt operator+(register pt &o) {return pt(x+o.x,y+o.y);} pt operator-(register pt &o) {return pt(x-o.x,y-o.y);} ll operator*(register pt o) {return (ll)x*o.y-(ll)y*o.x;} void operator+=(register pt &o) {x+=o.x;y+=o.y;} void operator-=(register pt &o) {x-=o.x;y-=o.y;} }; pt sl[K][N],sr[K][N],ss[K][N]; pt st[N],la[N],lb[N]; ll sa[N]; int l[M],a[N],r[M],cs[M],lcd[M],rcd[M],scd[M]; int n,i,j,x,y,z; inline void mx(register ll &x,const ll y) { if (x<y) x=y; } inline void read(int &x) { int c=getchar(),fh=1; while (c<48||c>57) { if (c=='-') {c=getchar();fh=-1;break;} c=getchar(); } x=c^48;c=getchar(); while ((c>=48)&&(c<=57)) { x=x*10+(c^48); c=getchar(); } x*=fh; } void tb(register pt *a,int pre,register int &n) { register int i,tp=pre; for (i=tp+1;i<=n;i++) { while (tp) { if (a[tp].y<=a[i].y) --tp; else if ((tp>1)&&(a[i]-a[tp-1]<a[tp]-a[tp-1])) --tp; else break; } a[++tp]=a[i]; } n=tp; } void maintain(register pt *a,const int n,const int m) { register int i; for (i=m;i>n;i--) a[a[i].x=i].y=inf; for (i=n;i;i--) {a[a[i].x]=a[i];a[a[i].x=i].y=inf;} } void spemaintain(register pt *a,const int n,const int m) { register int tp=0,i; for (i=1;i<=m;i++) st[st[i].x=i].y=inf; for (i=1;i<=n;i++) mx(st[a[i].x].y,a[i].y); memcpy(a+1,st+1,m*sizeof(pt)); } int order(register pt *a,register int n) { register int i=1,tp=0; for (i=1;i<=n;i++) if (a[i].y>inf) a[++tp]=a[i]; tb(a,1,tp);return tp; } int sum(pt *a,pt *b,pt *c,int n,int m,int len)//a+b=c { int i,j,tp=2; c[1]=a[1]+b[1]; for (i=1;i<n;i++) la[i]=a[i+1]-a[i];la[n]=a[1]-a[n]; for (i=1;i<m;i++) lb[i]=b[i+1]-b[i];lb[m]=b[1]-b[m]; for (i=j=1;(i<=n)||(j<=m);++tp) {if ((j>m)||(i<=n)&&(la[i]<lb[j])) c[tp]=c[tp-1]+la[i++]; else c[tp]=c[tp-1]+lb[j++];} --tp;spemaintain(c,tp,len);tp=order(c,len);tb(c,1,tp);return tp; } void build(int x) { if (l[x]==r[x]) { lcd[x]=rcd[x]=scd[x]=1;sl[cs[x]][l[x]]=sr[cs[x]][l[x]]=ss[cs[x]][l[x]]=pt(1,a[l[x]]); return; } register int c,cd; register ll ys; l[c=x<<1]=l[x];r[c]=l[x]+r[x]>>1; l[c|1]=r[c]+1;r[c|1]=r[x]; cs[c]=cs[c|1]=cs[x]^1; build(c);build(x<<1|1);c=x<<1; memset(ss[cs[x]]+l[x],0,(r[x]-l[x]+1)*sizeof(pt)); memset(sl[cs[x]]+l[x],0,(r[x]-l[x]+1)*sizeof(pt)); memset(sr[cs[x]]+l[x],0,(r[x]-l[x]+1)*sizeof(pt)); scd[x]=sum(sr[cs[c]]+l[c]-1,sl[cs[c]]+l[c|1]-1,ss[cs[x]]+l[x]-1,rcd[c],lcd[c|1],r[x]-l[x]+1); maintain(ss[cs[x]]+l[x]-1,scd[x],r[x]-l[x]+1); for (register int i=0;i<scd[c];i++) mx(ss[cs[x]][l[x]+ss[cs[c]][l[c]+i].x-1].y,ss[cs[c]][l[c]+i].y); memcpy(sl[cs[x]]+l[x],sl[cs[c]]+l[c],lcd[c]*sizeof(pt));lcd[x]=lcd[c];cd=r[c]-l[c]+1;ys=sa[r[c]]-sa[l[c]-1];c|=1; for (register int i=0;i<lcd[c];i++) sl[cs[x]][l[x]+(lcd[x]++)]=pt(sl[cs[c]][l[c]+i].x+cd,ys+sl[cs[c]][l[c]+i].y); tb(sl[cs[x]]+l[x]-1,lcd[c^1],lcd[x]); for (register int i=0;i<scd[c];i++) mx(ss[cs[x]][l[x]+ss[cs[c]][l[c]+i].x-1].y,ss[cs[c]][l[c]+i].y); scd[x]=order(ss[cs[x]]+l[x]-1,r[x]-l[x]+1); memcpy(sr[cs[x]]+l[x],sr[cs[c]]+l[c],rcd[c]*sizeof(pt));rcd[x]=rcd[c];cd=r[c]-l[c]+1;ys=sa[r[c]]-sa[l[c]-1];c^=1; for (register int i=0;i<rcd[c];i++) sr[cs[x]][l[x]+(rcd[x]++)]=pt(sr[cs[c]][l[c]+i].x+cd,ys+sr[cs[c]][l[c]+i].y); tb(sr[cs[x]]+l[x]-1,rcd[c^1],rcd[x]); } int main() { ll ans=9e18; int aa,bb,sss; read(n);read(aa);read(bb);read(sss); for (i=1;i<=n;i++) read(a[i]),sa[i]=sa[i-1]+a[i]; r[l[1]=1]=n;build(1); for (i=1;i<=scd[1];i++) { x=ss[cs[1]][i].x; ll y=ss[cs[1]][i].y;int s=sss; for (j=0;s>y&&s>1;j++) { ans=min(ans,(ll)bb*j+(ll)aa*((s-y-1)/x+1)); s=s+1>>1; } if (s>y) ans=min(ans,(ll)bb*j+(ll)aa*((s-y-1)/x+1)); else ans=min(ans,(ll)bb*j); } printf("%lld",ans); } ```