hdu3415单调队列

题意:
      给你一个数字组成的环,要求在里面找到一个最大的子序列,使得和最大,要求:
(1)子序列长度不能超过k
(2)如果子序列和相同要起点最小的
(3)如果起点相同要长度最小的


思路:
      首先环我们可以把序列放大一倍,然后Ans = maxx(sum[j] - sum[i]);  其中j>i,j-i>=k,sum[i]是前缀和,对于每一个j我们只要找到前面最小的那个sum[i]就行了,这样就变成了一个比较裸的一个单调队列的题目,求最小我们的队列可以使递增的,每次从队尾进,把比当前大的出队(不是大于等于,是大的,这样保证同样和的时候前缀最小),队头的话只要把距离当前值距离大于k的出队就行了,还有就是记住一点,每次都是先询问在进队,那么在询问之前一定要判断下队头的id是否过期,也就是队头是否要出先队列,这个地方大一了wa了一发。 




#include<stdio.h>
#include<string.h>


#define N 200000 + 10


typedef struct
{
   int id ,num;
}NODE;


NODE Q[N];
int num[N];
int tou ,wei ,k;


void insert(int id ,int num)
{
   for(int i = wei ;i > tou ;i --)
   if(Q[i].num > num) wei --;
   else break;
   Q[++wei].id = id;
   Q[wei].num = num;
   for(int i = tou + 1 ;i <= wei ;i ++)
   if(id - Q[i].id > k)  tou ++;
   else break;
}


int main ()
{
   int t ,n ,j ,i;
   int Ansa ,Ansb ,Ansc;
   scanf("%d" ,&t);
   while(t--)
   {
      scanf("%d %d" ,&n ,&k);
      for(i = 1 ;i <= n ;i ++)
      {
         scanf("%d" ,&num[i]);
         num[i+n] = num[i];
      }
      Ansc = - 1000000000;
      tou = wei = 0;
      int sum = 0;
      Q[++wei].num = 0;
      Q[wei].id = 0;
      num[0] = 0;
      for(i = 1 ;i <= n + n ;i ++)
      {
         sum += num[i]; 
         while(i - Q[tou+1].id > k)
         tou ++;  
         int now = sum - Q[tou+1].num;
         if(now > Ansc)
         Ansc = now ,Ansa = Q[tou+1].id + 1,Ansb = i;   
         insert(i ,sum);
      }
      if(Ansb > n) Ansb -= n;
      printf("%d %d %d " ,Ansc ,Ansa ,Ansb);
   }
   return 0;
}
      
      
      
   
   
   
   






      
   













原文地址:https://www.cnblogs.com/csnd/p/12062610.html