Loading

题解 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;
}
posted @ 2020-11-12 20:12  fpjo  阅读(108)  评论(0编辑  收藏  举报