[ARC119E]Pancakes

壹、题目描述 ¶

传送门 to Atcoder.

贰、题解 ¶

遇到过一道可以转化到那上面的题。

首先有一种二位偏序的想法:

House from \(\sf XYX\)

算是非常经典的一道题吧(\(\sf ZXY\) 金句)

我们发现翻转一个区间 \([l,r]\),两边和中间的相邻数字差都不会变,只有左右端点附近会变,具体地,会令答案加上

\[|S_{r+1}-S_l|+|S_{r}-S_{l-1}|-(|S_{r+1}-S_{r}|+|S_l-S_{l-1}|) \]

这里有四个绝对值,后面两个绝对值分别与 \(r\)\(l\) 单独相关,前面两个就得分类讨论了。

我们不妨令 \(S_{r+1}=x,S_r=y\;,\;S_l=a,S_{l-1}=b\) ,那么前面两个绝对值就是

\[|x-a|+|y-b| \]

我们想得到这个减去 \(|x-y|+|a-b|\) 的 最小值。

先鲁莽地讨论讨论(由于是取最值,下面全是可取等的也没问题了):

  1. \(x\geq a,y\geq b:\quad (x+y)-(a+b)\)
  2. \(x\geq a,y\leq b:\quad (x-y)-(a-b)\)
  3. \(x\leq a,y\geq b:\quad (y-x)-(b-a)\)
  4. \(x\leq a,y\leq b:\quad -(x+y)+(a+b)\)

然后我们其实没必要区分 \((x,y)\)\((a,b)\) 的前后关系,因此其实可以省掉 \(\rm case\ 3,4\) ,只讨论 \(1,2\).

分类讨论后,这其实就是个二维偏序。随便用什么数据结构或者直接 \(\tt CDQ\) 分治都行。

复杂度 \(\mathcal O(n\log n)\).

具体地说,就是将 \((S_i,S_{i+1})\) 看成一个点 \(P\),对于另外的点 \(Q\) 看它和 \(P\) 的位置关系了,而这个位置关系则可以使用数据结构或者 \(\tt CDQ\) 分支解决。

但是还有一种更好的方法,请先了解 [CF1513F]Swapping Problem 的原理。

如果我们记 \(b_i=a_{i+1}\),那么我们的初始答案就是

\[\sum_{i=1}^{n-1}\mid a_i-b_i\mid \]

考虑如果我们交换 \(i+1,j+1\) 这两个位置,那么我们的答案增加量就是

\[\Delta=\mid a_i-a_j\mid +\mid b_i-b_j\mid -\mid a_i-b_i\mid -\mid a_j-b_j\mid \]

经过和上一道题类似的分类讨论之后,我们发现出现答案变优的情况只有 “同向相交”。

所以使用类似的处理方法就行了。

但是这样做过不了样例,为什么?考虑我们的 \(\Delta\) —— 在交换 \(i+1,j+1\) 这两个位置之后,它会对 \(i\) 产生影响,即 \(i\ge 1\),并且对于后面的数字也有影响,即 \(i+1+1\le n\Leftrightarrow i\le n-2\),所以,对于 \(i,j\),它们的取值范围都是 \([1,n-2]\),而我们的交换位置 \(i+1,j+1\) 就是 \([2,n-1]\)它们并没有包含 \(l=1\or r=n\) 的情况,对于这两种情况,别无他法,只能使用 \(\mathcal O(n)\) 进行暴力判断了。

总的时间复杂度还是 \(\mathcal O(n\log n)\),但是不需要任何数据结构或者高超的 \(\tt CDQ\) 分治!

叁、参考代码 ¶

const int maxn=300000;
const int inf=0x3f3f3f3f;
 
int a[maxn+5], n;
 
struct segment{
    int l, r, t;
    segment(){}
    segment(int L, int R, int T): l(L), r(R), t(T){}
    inline int operator <(const segment rhs) const{
        return r>rhs.r;
    }
}seg[maxn+5];
ll ans=0, ori=0;
 
inline void input(){
    n=readin(1);
    rep(i, 1, n) a[i]=readin(1);
    int x, y;
    rep(i, 1, n-1){
        x=a[i], y=a[i+1];
        if(x>y) seg[i]=segment(y, x, 1);
        else seg[i]=segment(x, y, 0);
        ans+=fab(x-y);
    }
    ori=ans;
}
 
int minn[2];
 
signed main(){
    input();
    sort(seg+1, seg+n+1);
    minn[0]=minn[1]=inf;
    int t, len=0;
    rep(i, 1, n-1){
        t=seg[i].t;
        if(minn[t]<seg[i].r) len=max(len, seg[i].r-max(minn[t], seg[i].l));
        minn[t]=min(minn[t], seg[i].l);
    }
    ans=ans-(len<<1ll);
    rep(i, 2, n-1) ans=min(ans, ori-fab(a[i-1]-a[i])+fab(a[i-1]-a[n]));
    rep(i, 2, n-1) ans=min(ans, ori-fab(a[i]-a[i+1])+fab(a[1]-a[i+1]));
    printf("%lld\n", ans);
    return 0;
}
posted @ 2021-05-19 22:28  Arextre  阅读(98)  评论(0编辑  收藏  举报