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;

}

 

你可能感兴趣的:(HDU)