hdu 4193(单调队列)

来源:互联网 发布:淘宝客服聊天话术技巧 编辑:程序博客网 时间:2024/06/05 10:43

题意:给你一个n项的序列,每次可以把序列的首项移动到末尾,显然一共可以构成 n 种序列,问一共有多少种序列满足条件:序列的前 i 项和都大于等于0(i:1~n)。

解题思路:这道题我想的复杂了,实际上单调队列的做法并不复杂。求前缀和就可以用sum[j]-sum[i-1],这个式子表示以第i的元素为首位的序列,然后以第j个元素结尾的前缀和。同一个序列的不同结尾的前缀和每次都是减sum[i-1],只有sum[j]不同,所以我们就求出sum[j]中最小的再减去sum[i-1]看是否小于0即可。也就是说,在第i个序列中,最小的前缀和都大于等于0,那么肯定是符合题意的序列。因此我们现在就是要求一个长度为n的区间里面sum[j]的最小值,也就是一个移动的固定区间求最值,用单调队列O(n)解决。


#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn = 1000005;int n,a[maxn<<1],sum[maxn];int head,tail,q[maxn];void InQueue(int i){while(head < tail && sum[i] <= sum[q[tail-1]]) tail--;q[tail++] = i;}void OutQueue(int i){while(head < tail && q[head] < i - n + 1) head++;}int main(){while(scanf("%d",&n),n){for(int i = 1; i <= n; i++){scanf("%d",&sum[i]);sum[i + n] = sum[i];}for(int i = 2; i < 2*n; i++)sum[i] += sum[i-1];head = tail = 0;for(int i = 1; i < n; i++)InQueue(i);int ans = 0;for(int i = n; i < 2*n; i++){InQueue(i);OutQueue(i);if(sum[q[head]] - sum[i-n] >= 0)ans++;}printf("%d\n",ans);}return 0;}


0 0
原创粉丝点击