环上最大连续和
给定N,K以及一个环:A[1],A[2],A[3],…A[N],其中A[1]的左边是A[N]。
求该环上最大的连续子段和,要求选出的子段长度不超过K。
输入描述:
第一行两个整数N和K。
接下来一行,N个整数表示A[i]。
输出描述:
输出题目要求的最大连续和。
链接:
https://www.nowcoder.com/questionTerminal/8db855bdae5b426cb08cab6b5e119d26
解析
普通的最大连续和用简单的dp就可以解决了。本题还要求这个最大连续和的序列长度不超过K。我们首先维护一个数组A的前缀和sum, 这样一来求区间 [ l , r ] [l,r] [l,r]的和就为: s u m [ r ] − s u m [ l − 1 ] sum[r]-sum[l-1] sum[r]−sum[l−1], 最大连续和问题可以转化为对于每个i,找到最小的j,满足 j − i < = k j-i<=k j−i<=k即可,即可转化为单调队列问题,用优先队列维护前缀和的最小值即可.
AC代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <fstream>
#define INF 0x3f3f3f
#define MEM0(a) memset(a,0,sizeof(a))
#define MEM1(a,b) memset(a,b,sizeof(b)
#define FOR0(a,b) for(int i=a;i<=b;i++)
#define FOR1(a,b) for(int i=a;i<b;i++)
#define FOR2(a,b) for(int i=a;i>=b;i--)
#define FOR3(a,b) for(int i=a;i>b;i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn=2e5+5;
const int maxm=1e5+5;
const int mod=1e9+7;
const int inf=1e9;
const double eps=1e-9;
const double PI=acos(-1.0);
int a[maxn];
struct node{
int id,x;
node(){};
bool operator<(const node& tmp)const{
return tmp.x<x;
}
}sum[maxn];
priority_queue<node> qq;
inline int min(int x,int y){
return x<y?x:y;
}
inline int max(int x,int y){
return x>y?x:y;
}
int main(){
int n,k;
scanf("%d %d",&n,&k);
sum[0].id=0,sum[0].x=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i].id=i;
sum[i].x=sum[i-1].x+a[i]; //求前缀和;
}
for(int i=n+1;i<=n+k;i++){
sum[i].id=i;
sum[i].x=sum[i-1].x+a[i-n];
}
int ans=-inf;
qq.push(sum[0]);
for(int i=1;i<=n+k;i++){
qq.push(sum[i]);
while(i-qq.top().id>k){
qq.pop();
}
ans=max(ans,sum[i].x-qq.top().x);
}
printf("%d\n",ans);
return 0;
}