题解 CF846C Four Segments
题意
给定长度为n的序列a,求出三个点i,j,k(0<=i<=j<=k<=n),使得a[1]+...+a[i]-a[i+1]-...-a[j]+a[j+1]+...+a[k]-a[k+1]-...-a[n]最大
思路
最开始没想出来,然后看了题解
先对序列求前缀和,设为\(sum\)
那么最大值为\(max\{ sum_i-(sum_j-sum_i)+(sum_k-sum_j)-(sum_n-sum_k)\}\)
化简后就是求\(max\{sum_i+sum_k-sum_j\}\)时\(i,j,k\)的位置
题解里面是枚举\(j\),然后再\(O(n)\)扫前缀和求\(sum_i,sum_k\)的最大值
但\(j\)是逐渐变化的,我们可以用单调队列来维护\(sum_k\)的最大值,至于\(sum_i\)的最大值直接维护即可
时间复杂度$ O(n)$
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,ansi,ansj,ansk,l=1,r=0;
int a[5010],q[5010];
signed main(){
long long ans=(-(1ll<<62));
scanf("%lld",&n);
for(int i=1;i<=n;i++){scanf("%lld",&a[i]);a[i]+=a[i-1];}
for(int i=1;i<=n;i++){
while(l<=r && a[i]>a[q[r]])r--;
q[++r]=i;
}
int ki=0,kk,sum1,sum2,sum3;
for(int j=0;j<=n;j++){
if(q[l]<j)l++;kk=q[l];
if(a[ki]<a[j])ki=j;
if(a[kk]+a[ki]-a[j]>ans)ans=a[kk]+a[ki]-a[j],ansi=ki,ansj=j,ansk=kk;
}
printf("%lld %lld %lld\n",ansi,ansj,ansk);
return 0;
}