[ARC119E]Pancakes
Posted Tan_tan_tann
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[ARC119E]Pancakes相关的知识,希望对你有一定的参考价值。
Pancakes
题解
很水的一道题
首先,它最多只能有一次翻转,而它的权值又是相邻的两项去绝对值,所以最多只会影响到两项的权值。
假设我们翻转的是
l
,
r
l,r
l,r,那么我们要求的就是
(
∣
a
l
−
a
l
−
1
∣
+
∣
a
r
−
a
r
+
1
∣
−
∣
a
r
−
a
l
−
1
∣
−
∣
a
l
−
a
r
+
1
∣
)
max
\\left(\\left|a_{l}-a_{l-1}\\right|+\\left|a_{r}-a_{r+1}\\right|-\\left|a_{r}-a_{l-1}\\right|-\\left|a_{l}-a_{r+1}\\right|\\right)_{\\max}
(∣al−al−1∣+∣ar−ar+1∣−∣ar−al−1∣−∣al−ar+1∣)max
我们可以将所有的
a
a
a看作一个点,那么每个绝对值就是一条线段,从
a
l
a_{l}
al到
a
l
+
1
a_{l+1}
al+1的有向线段。
我们要做的,就是交换两个线段的起点,使他们减小的覆盖面积最大。
于是,我们很容易就联想到了[CF1513F]Swapping Problem这道题。
只不过这道题要使的两条线段异向,而这道题只有同向才会产生贡献。
但这并不影响我们用相似的方法完成这道题。
我们可以先将所有得同向线段按照左端点排序,再记录下右端点前缀最大值。
对于线段
i
i
i,线段
i
−
1
i-1
i−1就是与它左端点相交的最近的线段,我们需要将它的前缀最大值更新进去。
而在右边,我们需要去二分出第一个右端点
>
>
>线段
i
i
i的右端点的线段,用它来更新有它右端点相交的长度。注意必须是严格大于,否则可能会被线段
i
i
i的右端点影响。
而在
i
i
i与右边二分的那一条线段之间,就是被它包含的线段,我们可以用
s
t
st
st表求出被它包含的最长线段长度。
由于第
n
n
n个点比较特殊,它没有向后连的线段,我们还要特别更新一下它们与其它点交换会带来的贡献。
时间复杂度
O
(
n
l
o
g
n
)
O\\left(nlog\\,n\\right)
O(nlogn)。
update 2021.5.18: 经PPL巨佬提醒发现好像直接用排完序后贪心就可以做,如果用基排排序的话可以做到
O
(
n
(
l
o
g
r
m
+
r
)
)
O(n(log_{r}m+r))
O(n(logrm+r))不过应该没人用基排吧
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 300005
#define lowbit(x) (x&-x)
#define reg register
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x7f7f7f7f;
const LL jzm=2333;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int n,a[MAXN],tot,tot1,tot2,maxx,st[25][MAXN],mlim[MAXN],lg[MAXN];LL ans;
struct ming{int a,b,id;}up[MAXN],dn[MAXN];
bool cmp(ming x,ming y){if(x.a==y.a)return x.b>y.b;return x.a<y.a;}
int query(int l,int r){if(l>r)return 0;int k=lg[r-l+1];return max(st[k][l],st[k][r-(1<<k)+1]);}
signed main(){
read(n);for(int i=1;i<=n;i++)read(a[i]);LL maxx=0;
for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
for(int i=1;i<n;i++)ans+=1ll*Fabs(a[i]-a[i+1]);
for(int i=1;i<n;i++)
if(a[i]<a[i+1])up[++tot1]=(ming){a[i],a[i+1]};
else dn[++tot2]=(ming){a[i+1],a[i]};
sort(up+1,up+tot1+1,cmp);sort(dn+1,dn+tot2+1,cmp);
for(int i=1;i<=tot1;i++)st[0][i]=up[i].b-up[i].a,mlim[i]=max(mlim[i-1],up[i].b);
for(int i=1;i<=lg[tot1];i++)
for(int j=1;j<=tot1-(1<<i)+1;j++)
st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
for(int i=1;i<=tot1;i++){
maxx=max(maxx,2ll*(min(up[i].b,mlim[i-1])-up[i].a));int l=i+1,r=tot1;
while(l<r){int mid=l+r>>1;if(mlim[mid]>up[i].b)r=mid;else l=mid+1;}
maxx=max(maxx,2ll*query(i+1,min(tot1,l-1)));
if(l<=tot1&&up[l].b>up[i].b)maxx=max(maxx,2ll*(up[i].b-up[l].a));
}
for(int i=1;i<=tot2;i++)st[0][i]=dn[i].b-dn[i].a,mlim[i]=max(mlim[i-1],dn[i].b);
for(int i=1;i<=lg[tot2];i++)
for(int j=1;j<=tot2-(1<<i)+1;j++)
st[i][j]=max(st[i-1][j],st[i-1][j+(1<<i-1)]);
for(int i=1;i<=tot2;i++){
maxx=max(maxx,2ll*(min(dn[i].b,mlim[i-1])-dn[i].a));int l=i+1,r=tot2;
while(l<r){int mid=l+r>>1;if(mlim[mid]>dn[i].b)r=mid;else l=mid+1;}
maxx=max(maxx,2ll*query(i+1,min(tot2,l-1)));
if(l<=tot2&&dn[l].b>dn[i].b)maxx=max(maxx,2ll*(dn[i].b-dn[l].a));
}
for(int i=2;i<n;i++)
maxx=max(maxx,1ll*Fabs(a[i]-a[i-1])-1ll*Fabs(a[n]-a[i-1])),
maxx=max(maxx,1ll*Fabs(a[i+1]-a[i])-1ll*Fabs(a[1]-a[i+1]));
printf("%lld\\n",ans-maxx);
return 0;
}
谢谢!!!
以上是关于[ARC119E]Pancakes的主要内容,如果未能解决你的问题,请参考以下文章
iOS ARC:xcode编译器在arc下给代码添加retain和release的原理是啥?