当前位置: 代码迷 >> 综合 >> 1201 最大子序和
  详细解决方案

1201 最大子序和

热度:91   发布时间:2024-01-15 06:54:53.0

描述

输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。

例如 1,-3,5,1,-2,3

当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6

输入格式

第一行两个数n,m(n,m<=300000)
第二行有n个数,要求在n个数找到最大子序和

输出格式

一个数,数出他们的最大子序和

样例输入

6 4
1 -3 5 1 -2 3

样例输出

7

分析:

序列和先转化为前缀问题,即a[x]+a[x+1]+.......a[y-1]+a[y]=sum[y]-sum[x-1],

问题就变为:找出两个位置x,y,满足sum[y]-sum[x]最大且满足y-x<=m

我们枚举右端点y,当y的固定的时候,问题又变为:找到左端点x,x属于[y-m,y-1]并且sum[x]最小。

即在一定范围内维护一个最小的值,典型的单调队列

 

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<stack>
#include<string>
#include<vector>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int N=300010;
deque<int>q;
int sum[N];
int main()
{int n,m; scanf("%d%d",&n,&m);q.clear();sum[0]=0;int ans=-(1<<30);q.push_back(0);for(int i=1;i<=n;i++){int v;scanf("%d",&v);sum[i]=sum[i-1]+v;while(!q.empty() && q.front()<i-m) q.pop_front();ans=max(ans,sum[i]-sum[q.front()]);while(!q.empty() && sum[q.back()]>=sum[i]) q.pop_back();q.push_back(i);}printf("%d\n",ans);return 0;
}