[CTSC2009] 序列变换
foreverlasting · · 题解
写这篇题解的主要目的是好好普及下
题意:给出一个序列
题解:一道有范围限制且要构造方案的
首先注意到
考虑一个暴力
好像和平时遇到的
我们继续考虑
于是,每一次平移之后,凸包非
于是就剩下构造答案了,首先得知道三个性质。
性质一:我们在维护这个凸包的时候,除了维护每个斜率变化的分界点外,还维护了最低点的纵坐标值。于是在最后的凸包里,我们知道
性质二:我们要清晰知道一件事,在
性质三:我们要知道一个显然的贪心性质,在前面的凸包中,如果每次
有了以上的三个性质,我们就可以构造答案了。
性质三意味着在初步构造中,我们可以贪心地让每个
于是就顺利构造出一组答案了,且一定是最小的(因为
代码实现上,我们不一定要真的对维护分界点的堆进行即时的截取。可以类似懒标记那样,对每个初步构造的
同时在这里也给出了所有
//2022.8.30 by ljz
//email [email protected]
//if you find any bug in my code
//please tell me
const int N=5e5+10;
namespace MAIN {
int n,mx,p,q;
int a[N];
LL b[N];
priority_queue<LL> L;
priority_queue<LL,vector<LL>,greater<>> R;
inline void MAIN(const int &Case) {
n=read(),mx=read(),p=read(),q=read();
for(int i=1;i<=n;i++)a[i]=read();
LL tagl=0,tagr=0;
L.push(a[1]),R.push(a[1]),b[1]=a[1];
for(int i=2;i<=n;i++){
tagl+=p,tagr+=q;
LL l=L.top()+tagl,r=R.top()+tagr;
if(a[i]<l)L.pop(),R.push(l-tagr),L.push(a[i]-tagl),L.push(a[i]-tagl);
else if(a[i]>r)R.pop(),L.push(r-tagl),R.push(a[i]-tagr),R.push(a[i]-tagr);
else L.push(a[i]-tagl),R.push(a[i]-tagr);
LL t=L.top()+tagl;
b[i]=min((LL)mx,max((LL)p*(i-1)+1,t));
}
for(int i=n-1;i>=1;i--){
if(b[i]>b[i+1]-p)b[i]=b[i+1]-p;
if(b[i]<b[i+1]-q)b[i]=b[i+1]-q;
}
LL ans=0;
for(int i=1;i<=n;i++)ans+=abs(a[i]-b[i]);
printf("%lld\n",ans);
}
}