考虑枚举每个子串开头的位置,然后答案转化成询问这个位置之后 哪个位置的前缀和 - 这位置的前缀和 最大(当然是已经把绝对值和正负的情况处理好了,可以发现按奇偶,这个序列只有两种情况),只需要预处理这两个序列的前缀和,以及这两个前缀和序列的后缀max即可。
#include<cstdio> #include<iostream> using namespace std; typedef long long ll; int Abs(int x){ return x<0 ? (-x) : x; } int n; int a[100010],b[100010]; ll d[100010],c[100010],e[100010],f[100010],ans; int main(){ // freopen("c.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); } for(int i=1;i<n;++i){ b[i]=Abs(a[i+1]-a[i]); } int op=1; for(int i=1;i<n;++i){ c[i]=c[i-1]+(ll)(b[i]*op); op=-op; } op=-1; for(int i=1;i<n;++i){ d[i]=d[i-1]+(ll)(b[i]*op); op=-op; } ll maxn=-1e18; for(int i=n-1;i>=1;--i){ maxn=max(maxn,c[i]); e[i]=maxn; } maxn=-1e18; for(int i=n-1;i>=1;--i){ maxn=max(maxn,d[i]); f[i]=maxn; } for(int i=1;i<n;i+=2){ ans=max(ans,e[i]-c[i-1]); } for(int i=2;i<n;i+=2){ ans=max(ans,f[i]-d[i-1]); } cout<<ans<<endl; return 0; }