hdu3415:最大k子段和,单调队列

题目大意:
给定长度为n的数组,求出最大的区间和,其中区间长度在[1,k]之间

分析:

学动态规划的时候我们会遇到一个经典问题

最大子段和,这个题跟最大子段和很类似 不同的是区间的长度有限制,无法用原算法解决

转换思路

区间[i,j]的和就是ans=sum(j)-sum(i-1) ( j - i <=k)

那么对于每个j 我们肯定希望sum(i-1)最小,所以我们只需要对sum(i-1)维护一个单调队列,然后依次增加 j

同时将单调队列中不满足( j - i <k)的元素出队即可

代码:

#include <iostream>
#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<ctype.h>
using namespace std;
#define maxn 10000010
typedef struct Node
{
    int val;
    int num;
}node;
typedef struct dqueue
{
    node q[maxn];
    int l,r;
    void ini()
    {
        l=0;
        r=0;
    }
    node front()
    {
        return q[l];
    }
    node pop()
    {
        l++;
        return q[l-1];
    }
    void push(node x)
    {
        if(r==l)
        {
            q[r++]=x;
            return;
        }
        if(x.val<q[l].val)
        {
            r=l;
            q[r++]=x;
            return;
        }
        while(r>=1&&(x.val<q[r-1].val))
        {
            r--;
        }
        q[r++]=x;
    }
}Dqueue;
int a[200020];
int sum[200020];
Dqueue q;
int main()
{
    int n,k,T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",a+i);
        }
        memcpy(a+n+1,a+1,n*sizeof(int));
        for(int i=1;i<=2*n;i++)
        {
            sum[i]=sum[i-1]+a[i];
        }
        node x;
        node tmp;
        int t=0;
        q.ini();
        int ans=-10000;
        int l,r;
        for(int i=1;i<=2*n;i++)
        {
            x.val=sum[i-1];
            x.num=i-1;
            q.push(x);
            while(1)
            {
                tmp=q.front();
                if(i-tmp.num>k)
                {
                    q.pop();
                }
                else
                {
                    break;
                }
            }
            if(sum[i]-tmp.val>ans)
            {
                ans=sum[i]-tmp.val;
                l=tmp.num+1;
                r=i;
                continue;
            }
        }
        if(r>n)
        {
            r-=n;
        }
        printf("%d %d %d\n",ans,l,r);
    }
    return 0;
}

 

posted @ 2014-10-24 17:59  PlasticSpirit  阅读(528)  评论(0编辑  收藏  举报