Hlg 1522 子序列的和 <单调队列>

题意:

给一串数字长度n 和 取值长度范围m

还有这串数字..a0, a1, a2, a3, ..., an

求这串数字中在 长度范围m 内和sum 最大的..

思路:

从1~n 遍历每一个数..

当前数字串和S(i) - 以前数字串和中的最小那个S(i-k){1 < k <m}<以前数字串的‘以前’范围是取值长度范围>

‘以前数字串和中的最小那个’可以用 单调队列que 来控制..

取遍历结果中最小那个..

Tips:

主要讲一下什么是单调队列..

单调队列..顾名思义就是 单调增或减的队列..它存的值是对应 和数组s 里的下标..

其中队头元素是 队列s 最大值或最小值的下标..

 

但是其实这个队列不是实际存在的..

而是用在一个大队列里..找出符合条件的单调小队列..

然后根据这个单调小队列来解题..

找单调小队列靠一个队头指针front 和 一个队尾指针 rear

 

把下标加入一个大的队列里..

然后根据条件调整队头指针和队尾指针..

而条件就是

①. 队头元素:在 front指针 <= rear 指针的前提下.. 队头元素的下标在给定范围内..

②. 队尾元素:在 front指针 <= rear 指针的前提下.. 若是单调递增队列..即队头元素是最小的..so..新插入的队尾元素的值应该要比原队尾的值大..保证插入新队尾元素后这个队列还是单调递增队列..

                                                                若是单调递减队列..即队头元素是最大的..so..新插入的队尾元素的值应该要比原队尾的值小..保证插入新队尾元素后这个队列还是单调递减队列..

 

eg:

假设数列为:8,7,12,5,16,9,17,2,4,6.N=10,k=3.

 

那么我们构造一个长度为3的单调递减队列:

 

首先,那8和它的索引0放入队列中,我们用(8,0)表示,每一步插入元素时队列中的元素如下:

 

0:插入8,队列为:(8,0)

 

1:插入7,队列为:(8,0),(7,1)

 

2:插入12,队列为:(12,2)

 

3:插入5,队列为:(12,2),(5,3)

 

4:插入16,队列为:(16,4)

 

5:插入9,队列为:(16,4),(9,5)

 

。。。。依此类推

 

那么f(i)就是第i步时队列当中的首元素:8,8,12,12,16,16,。。。

 

例子自【转】自:http://blog.csdn.net/Justmeh/article/details/5844650#reply    感觉博主讲得挺详细挺清楚的..就是code貌似有点问题..

 

最后这道题单调小队列的结果就是 在 取值长度范围m 内和单调递增的 对应下标值..

Code:

 

View Code
 1 #include <stdio.h>

 2 #include <cstring>

 3 #define clr(x) memset(x, 0, sizeof(x))

 4 

 5 int que[100010];

 6 int s[100010];

 7 

 8 int buffer(int n, int len)

 9 {

10 

11     int i, j, k;

12     int front = 0, rear = -1;

13     int res = -99999999;

14 

15     for(i = 1; i <= n; ++i){

16         while(front <= rear && que[front] < i-len)

17             front++;

18 

19         while(front <= rear && s[i-1] < s[que[rear]])

20             rear--;

21 

22         que[++rear] = i-1;

23 

24         if(res < s[i]-s[que[front]])

25             res = s[i]-s[que[front]];

26     }

27 

28     return res;

29 }

30 

31 int main()

32 {

33     int i, j, k;

34     int num;

35     int n, m;

36     while(scanf("%d %d", &n, &m) != EOF)

37     {

38         clr(que);

39         clr(s);

40         for(i = 1; i <= n; ++i){

41             scanf("%d", &num);

42             s[i] = s[i-1]+num;

43         }

44 

45         printf("%d\n", buffer(n, m));

46     }

47     return 0;

48 }

 

 

 

你可能感兴趣的:(队列)