luogu 2629 好消息,坏消息
题目描述
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
分析
跟这道题是一样的
我们用前缀和方便求区间和
由于是环形,开两倍
朴素算法,每到一个点时,判断以任意点为起点时的区间和是否小于零,如果小于零,那么不能做为起点
也就是说,每次只保留令sum[i] - sum[j] >= 0的j,到最后剩下的点就是合法起点
也就是满足sum[j-1]<=sum[i]的点保留
嗯?有点眼熟?、
单调队列不就是这个操作嘛
每次入队新值前都会弹出比他大(或小)的值以维护队列单调
OK
代码
1 /********************** 2 User:Mandy.H.Y 3 Language:c++ 4 Problem: luogu 2629 5 Algorithm: 6 **********************/ 7 8 #include<bits/stdc++.h> 9 10 using namespace std; 11 12 const int maxn = 1e6 + 5; 13 14 int n,ans; 15 int a[maxn << 1]; 16 int sum[maxn << 1]; 17 int l,r,q[maxn << 1]; 18 19 template<class T>inline void read(T &x){ 20 x = 0;bool flag = 0;char ch = getchar(); 21 while(! isdigit(ch)) flag |= ch == '-',ch = getchar(); 22 while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar(); 23 if(flag) x = -x; 24 } 25 26 template<class T>void putch(const T x){ 27 if(x > 9) putch(x / 10); 28 putchar(x % 10 | 48); 29 } 30 31 template<class T>void put(const T x){ 32 if(x < 0) putchar('-'),putch(-x); 33 else putch(x); 34 } 35 36 void file(){ 37 freopen("2629.in","r",stdin); 38 freopen("2629.out","w",stdout); 39 } 40 41 void readdata(){ 42 read(n); 43 for(int i = 1;i <= n; ++ i) read(a[i]),a[i+n]=a[i]; 44 for(int i = 1;i <= n + n; ++ i) sum[i] = sum[i - 1] + a[i]; 45 } 46 47 void work(){ 48 49 for(int i = 1;i <= n + n; ++ i){ 50 while(l < r && q[l] + n <= i ) ans++,l++; 51 q[r++] = i; 52 while(l < r && sum[q[r-1]-1] > sum[i]) r--; 53 54 } 55 put(ans); 56 } 57 58 int main(){ 59 // file(); 60 readdata(); 61 work(); 62 return 0; 63 }
非做顽石不可,哪管他敬仰暗唾