传送门
题目大意
给定一段长度为n序列,选择两个不连续的长度均为k的区间,[L,L+1,L+2,....,L+k-1],[R,R+1,R+2,...,R+k-1](R >= L+k),求这两个区间和的最大值。
思路
求区间和肯定可以想到用前缀和了,但是怎么找这两个区间呢?我一开始想的是把n-k+1个子区间的和都求出来然后用二重循环去找,但是发现肯定超时,所以要改变一下思路。可以把前i个数中长度为k的区间的和的最大值求出来,然后跟以i+1为起点的长度为k的区间和相加,随着i的增大不断更新最大值,这样子就只需要一重循环就可得出答案。这么做为什么可以呢?为了方便说明,把要找的两个区间一个叫做左区间,一个叫做右区间。在循环过程中,我们其实遍历了所有的右区间,然后让右区间都与其左边的最大的长度为k子区间相加,很显然得到的结果自然就是我们想要的答案。还有一点要说明,初始值ans一定要赋值一个很小的数,我做的时候连续WA了好几发在第5个测试点,后来去看别人的提交才改过的。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
ll a[N],b[N];
int main(){
int t,n,k;
scanf("%d",&t);
while (t--){
scanf("%d %d",&n,&k);
memset(b,0,sizeof(b));
for (int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=b[i-1]+a[i];
}
ll ans=-0x3f3f3f3f3f3f,pre=-0x3f3f3f3f3f3f;
for (int i=k;i<=n-k;i++){
pre=max(pre,b[i]-b[i-k]); //维护前i个数中长度为k的区间的最大值
ans=max(ans,pre+b[i+k]-b[i]);
}
printf("%lld\n",ans);
}
return 0;
}