TYVJ1305 最大子序和

P1305 最大子序和
时间: 1000ms / 空间: 131072KiB / Java类名: Main

描述

输入一个长度为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个数,要求在n个数找到最大子序和

输出格式

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

测试样例1

输入

6 4
1 -3 5 1 -2 3

输出

7

备注

数据范围:
100%满足n,m<=300000
 
【题解】
给前缀和维护一个单调递增的队列
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #define max(a, b) ((a) > (b) ? (a) : (b))
 6 #define min(a, b) ((a) < (b) ? (a) : (b))
 7 
 8 inline void swap(int &a, int &b)
 9 {
10     int tmp = a;a = b;b = tmp;
11 }
12 
13 inline void read(int &x)
14 {
15     x = 0;char ch = getchar(), c = ch;
16     while(ch < '0' || ch > '9')c = ch, ch = getchar();
17     while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();
18     if(c == '-')x = -x;
19 }
20 
21 const int INF = 0x3f3f3f3f;
22 const int MAXN = 300000 + 10;
23 
24 int n, m, sum[MAXN], q[MAXN], rank[MAXN], head, tail, ans;
25 
26 int main()
27 {
28     read(n), read(m);
29     for(register int i = 1;i <= n;++ i) read(sum[i]), sum[i] += sum[i - 1];
30     head = tail = 1;
31     ans = -INF;
32     for(register int i = 1;i <= n;++ i)
33     {
34         while(i - rank[head] > m)++ head;
35         ans = max(ans, sum[i] - q[head]);
36         while(q[tail] >= sum[i] && tail >= head)-- tail;
37         ++ tail; 
38         q[tail] = sum[i], rank[tail] = i;
39         
40     } 
41     printf("%d", ans);
42     return 0;
43 }
TYVJ1305

 

posted @ 2017-09-19 07:48  嘒彼小星  阅读(238)  评论(0编辑  收藏  举报