Non-negative Partial Sums 单调队列

Non-negative Partial Sums


初学单调队列,纠结了好久这个题,一直没理解原理是怎么回事,网上搜解题报告一股脑看下去还是没看个明白、、、、、终于慢慢摸索出来了

首先理解这个题的意思:一个数列,可以将最前一个数放在最后,也就是这是个数列是环状的,比说1,-2,3这个数列可以写成-2,3,1,和3,1,-2两种循环方式

题目要求统计这个数列所有循环中每一个都满足前i(1<= i <=n)个数之和为非负数(>=0)的i的个数。

思路:从1到n枚举i,求出每一个循环状态前i个数之和min,若min<0则 i 不满足条件,否则ans累加计数。然后问题就是如果依次枚举循环求和肯定超时,如何优化?

大神有用线段树有用其他各种巧办法、、、这里写下单调队列希望比那些单调队列报告更好理解。

先借个图:http://www.2cto.com/kf/201311/255850.html


循环的状况一般都把数列再往后复制一遍(图中黄色)


sum[ i ]=a[1]+a[2]+...+a[i];

思路不变。图中红色方框从2向右就开始移动,每次都对应一个循环状态,单调队列维护红框中的sum[ ](递增),这是取单调队列q的第一个值q[ 0 ](红框中sum[ ]的最小值),

用sum[ q[0] ] 去减红框左边外面第一个数也就是sum[ 1 ],即sum[ q[0] ]-sum[ 1 ]=t,若 t >=0 说明所有循环状态中的前 1 个数的和都>=0,则ans可以计数。为什么呢。。。

想一下,若红框中有A[ i ] < 0 那么sum[ i ]相对sum[ i-1 ]必定是减少的,相对方框左边外面第一个sum[ ]肯定也是减少的,这样的一个差必为负,而为什么要取红框左外第一个数,因为我们红框右移同时左边外面的数列递增到k个,我们可以通过取红框内最小值去减这个数一次性判断前k个数之和是否>=0

当红框再向右移时,有  sum[ q[ 0 ] ] - sum[ 2 ] = t,同理,t >= 0说明所有循环状态中前2个数的和都 >=0,否则存在负数

q始终维护红框内的最小sum[ ],每次移动判断 sum[ q[ 0 ] ] - sum[ i - n ]的值正负状况(i为红框内最右一个数的下标)


#include<stdio.h>
#include<string.h>
#define MAXN 1000005
int q[MAXN*2];//单调队列
int sum[MAXN*2];
int main()
{
    int n,i;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0) break;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&sum[i]);
            sum[i+n]=sum[i];
        }
        for(i=1;i<=(n<<1);i++)
            sum[i]+=sum[i-1];
        int head=0,rear=0;
        int ans=0;
        for(i=2;i<=(n<<1);i++)
        {
            while(head<rear && sum[q[rear-1]]>=sum[i])
                --rear;
            q[rear++]=i;
            if(i>n&&sum[q[head]]-sum[i-n]>=0)
                ++ans;
            while(q[rear-1]-q[head]+1>n)
                ++head;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值