P2629 好消息,坏消息

58 篇文章 0 订阅
9 篇文章 0 订阅

https://www.luogu.com.cn/problem/P2629

题目描述

uim在公司里面当秘书,现在有n条消息要告知老板。每条消息有一个好坏度,这会影响老板的心情。告知完一条消息后,老板的心情等于之前老板的心情加上这条消息的好坏度。最开始老板的心情是0,一旦老板心情到了0以下就会勃然大怒,炒了uim的鱿鱼。

uim为了不被炒,知道了了这些消息(已经按时间的发生顺序进行了排列)的好坏度,希望研究如何不让老板发怒。

uim必须按照时间的发生顺序逐条将消息告知给老板。不过uim可以使用一种叫“倒叙”的手法,例如有n条消息,小a可以从k,k+1,k+2…n,1,2…k-1这种顺序通报。

他希望知道,有多少个k,从k开始通报到n然后从1通报到k-1可以让老板不发怒。

输入格式

第一行一个整数n(1 <= n <= 10^6),表示有n个消息。

第二行n个整数,按时间顺序给出第i条消息的好坏度Ai(-1000 <= Ai <= 1000)

输出格式

一行一个整数,表示可行的方案个数。

输入输出样例

输入 #1复制

4
-3 5 1 2 

输出 #1复制

2

说明/提示

样例解释

[5 1 2 -3]或[1 2 -3 5]

对于25%数据n<=1000

对于75%数据n<=10000

对于100%数据n<=10^6


思路:由于枚举的起点不确定,实际上是一个起点不定向整个序列长度一定环

那么比较常规的操作是破环为链(类似石子合并里面也出现了破环为链)

长度开两倍枚举起点

同时这个dp的转移由于复杂度超时,需要对一段求区间最大的用单调队列优化

单调队列维护dp的最值转移,注意减的时候的边界情况

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
typedef long long LL;
LL n;
LL a[maxn*2],sum[maxn*2];
LL q[maxn*2];
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  LL n;cin>>n;
  for(LL i=1;i<=n;i++) cin>>a[i];
  for(LL i=n+1;i<=n*2-1;i++) a[i]=a[i-n];//破环为链 
  for(LL i=1;i<=n*2-1;i++) sum[i]=sum[i-1]+a[i];
  LL ans=0;LL h=1;LL t=0;
  //维护sum[]中的最小值 
  for(LL i=1;i<=2*n-1;i++)
  {
  		while(h<=t&&max(q[h]+n-1,(LL)1)<i)  h++;
  		
  		while(h<=t&&sum[q[t]]>=sum[i])   t--;
  		q[++t]=i;
  		if(i>=n&& sum[q[h]]-sum[max((LL)0,i-n+1-1)]>=0 )   ans++;
  }
  cout<<ans<<endl;
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值