【单调队列】HDU4193

来源:互联网 发布:佛山网站推广优化公司 编辑:程序博客网 时间:2024/05/16 04:41

HDU4193:http://acm.hdu.edu.cn/showproblem.php?pid=4193

题目描述:有一串数列:a1,a2,a3,a4 .. an, 

它可以变形为 a2,a3,a4 .. an,a1 ;  

                      a3,a4 .. an,a1,a2 ;

                      a4 .. an,a1,a2,a3      等n种。

问有多少种变形的前缀和>=0?

例如 a1,a2,a3,a4 .. an 如果sum[1]>=0&&sum[2]>=0&&....&&sum[n]>=0则记为一种。

解法:单调队列。

首先将n个数扩展为2*n个数,然后求前缀和。sum[i]-sum[j]是j+1~i段的前缀和,

所以如果i~i+n-1段是的话,那么sum[i]-sum[i-1]>=0&&sum[i+1]-sum[i-1]>=0&&...&&sum[i+n-1]-sum[i-1]>=0,

所以min{sum[i..i+n-1]}-sum[i-1]>=0 则sum[i...i+n-1]-sum[i-1]>=0

因此,只要找出一段数中的最小值,就可以判断了。


一定要用scanf读数,否则在hdu中会超时。

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <algorithm>#include <map>#include <queue>using namespace std;//int a[100005];#define INF 1000000009#define ll long longint sum[2000005];int qq[2000005];int ind[2000005];int main(){int n;while(scanf("%d",&n)!=EOF&&n){int topp=1,endd=1;sum[0]=0;for(int i=1;i<=n;i++){scanf("%d",&sum[i]);sum[i+n]=sum[i];}for(int i=1;i<=2*n;i++){sum[i]+=sum[i-1];}int cnt=0;for(int i=1;i<=2*n;i++){if(topp!=endd&&i-ind[topp]+1>n){topp++;}if(topp==endd){qq[endd]=sum[i];ind[endd]=i;endd++;}else if(sum[i]>=qq[endd-1]){qq[endd]=sum[i];ind[endd]=i;endd++;}else{while(endd>topp){if(sum[i]<qq[endd-1]){endd--;}elsebreak;}qq[endd]=sum[i];ind[endd]=i;endd++;}if(i>n){if(qq[topp]-sum[i-n]>=0)cnt++;}}printf("%d\n",cnt);}return 0;}


0 0
原创粉丝点击