HDU 4193 Non-negative Partial Sums(单调队列)



题目大意: 给定一个长度为n的循环序列,从n个不同位置开始,问有几个位置使得一下情况成立:所有前缀的和都大等于0(n <=1000000).

下午的训练赛,之前没学过单调队列所以用的线段树,一直tle,到了结束也没搞出来。晚上回来看了下,可以用单调队列来做,时间复杂度为O(n)。

这道题其实就是看从每个位置开始的最小前缀和是否大于零,但是这是有规律的。

比如从元素1(以下将元素a[i]简写为i)开始的所有前缀和为1,1+2,...,1+2+3+..+n

从2开始的所有前缀和为2, 2+3 ,....2+3+4+..+n+1

那么当我们算出以1开头的所有前缀的最小值(记为u)时,那么以2开头的所有前缀和的最小值为min(2+1, 2+3+1,...,2+3+4+..+n+1, 2+3+4+..+n+1+1)-1,

也就是说我们每次把sum[n]+sum[i]添加到队列中,求出最小值后减去sum[i]就是以i+1为首的所有前缀和的最小值。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#define eps 1e-6
#define LL long long
using namespace std;  

const int maxn = 1000000 + 1000;
const int INF = 0x3f3f3f3f;
int a[1000000+100];
int n;
int su[1000000+100];

int qmin[maxn], vmin[maxn], hmin = 1, tmin = 0;
void Min(int a, int i) {  //第i个元素a入队
	while(hmin<=tmin && vmin[hmin] <= i-n) hmin++;  //超范围队首出队
	//while(hmin<=tmin && qmin[tmin]>=a) tmin--; //不符合要求队尾出列
	int l = hmin, r = tmin;
	while(l <= r) {
		int m = l+(r-l)/2;
		if(qmin[m] >= a) r = m - 1;
		else l = m + 1;
	}
	tmin = ++r;
	qmin[tmin] = a;
	vmin[tmin] = i;
}

int main() {
	//freopen("input.txt", "r", stdin);
	while(scanf("%d", &n) == 1 && n) {
		hmin = 1, tmin = 0;
		for(int i = 1; i <= n; i++) {
			scanf("%d", &a[i]);
			su[i] = su[i-1] + a[i];
		}
		int ans = 0;
		for(int i = 1; i < n; i++) Min(su[i], i);
		for(int i = n; i < 2*n; i++) {
			Min(su[n]+su[i-n], i);
			if(qmin[hmin]-su[i-n] >= 0) ans++;
		}
		cout << ans << endl;
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-09 02:17:25

HDU 4193 Non-negative Partial Sums(单调队列)的相关文章

HDU 6444 Neko&#39;s loop(单调队列)

Neko has a loop of size nn. The loop has a happy value aiai on the i−th(0≤i≤n−1)i−th(0≤i≤n−1) grid. Neko likes to jump on the loop.She can start at anywhere. If she stands at i−thi−thgrid, she will get aiai happy value, and she can spend one unit ene

HDU 4122 Alice&#39;s mooncake shop 单调队列优化dp

Alice's mooncake shop Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=4122 Description The Mid-Autumn Festival, also known as the Moon Festival or Zhongqiu Festival is a popular harvest festival celebrated by Ch

HDU 3415 Max Sum of Max-K-sub-sequence 单调队列题解

本题又是一题单调队列题解. 技巧就是需要计算好前n项和Sn = a1 + a2 + ... an 这样方便处理. 记录一条单调队列,其意义是: q(head), q(head+1), ...q(tail) 其中头q(head)代表当前最佳解的起点 这样我们只需要在求某点为结尾的S[i] - S[q(head)就得到当前最佳值. 了解了单调数列,知道其中的记录意义,那么这道题就没有难度了.我也是了解这些信息之后就自己敲出代码的. 不过有些细节没写好也让我WA了几次. 最近少刷水题,而一直都是每天一

hdu 4122 Alice&#39;s mooncake shop(单调队列)

题目链接:hdu 4122 Alice's mooncake shop 题目大意:给定N和M,表示有N个订单,M个时刻可以做月饼,时刻以小时计算,任意时刻可以做若干个月饼.接着 N行为N个订单的信息,包括时间和数量.再给定T和S,表示每个月饼的保质时间和每保存一小时的开销.然后M行为 对应每个时刻制作月饼的代价.问说最少花费多少代价完成所有订单. 解题思路:单调队列或者RMQ,单调队列即用一个deque维护一个代价递增的队列,每次将头部保质期不够的剔除. RMQ可以将预处理处每个区间时刻代价的最

HDU 4123 Bob&#39;s Race:单调队列 + st表

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4123 题意: 给你一棵树,n个节点,每条边有长度. 然后有m个询问,每个询问给定一个q值. 设dis[i]为:从节点i出发,不重复经过节点,所能够走的最远距离. 每次询问问你:区间[l,r]最长能有多长,同时保证 max{dis[i]} - min{dis[i]} <= q (i∈[l,r]) 题解: 首先有一个结论: 从树上的任意一个节点出发,尽可能往远走,最终一定会到达树的直径的两个端点之一.

HDU 5380 Travel with candy (单调队列&amp;贪心)

本文纯属原创,转载请注明出处.http://blog.csdn.net/zip_fan,谢谢. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5380. Travel with candy Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Problem Description There are n+1 cities on

hdu 3415 Max Sum of Max-K-sub-sequence(单调队列)

题目链接:hdu 3415 Max Sum of Max-K-sub-sequence 题意: 给你一串形成环的数,让你找一段长度不大于k的子段使得和最大. 题解: 我们先把头和尾拼起来,令前i个数的和为sum[i]. 然后问题变成了求一个max{sum[i]-sum[j]}(i-k<j<i) 意思就是对于每一个sum[i],我们只需要找一个满足条件的最小的sum[j],然后我们就可以用一个单调队列来维护. 1 #include<bits/stdc++.h> 2 #define F

HDU 3706 Second My Problem First (单调队列)

题意:求给定的一个序列中最长子序列,该子序列的最大值和最小值介于m和k之间. 析:用两个单调队列来维护一个最小值,一个最大值,然后每次更新即可. 代码如下; #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <i

hdu 5056 Boring count (类似单调队列的做法。。)

给一个由小写字母构成的字符串S,问有多少个子串满足:在这个子串中每个字母的个数都不超过K. 数据范围: 1<=T<= 1001 <= the length of S <= 1000001 <= K <= 100000 思路: 考虑以S[i]结尾的子串,若以S[j] (j<i)作为头不能构成一个符合条件的子串,则S[1]...S[j]都不能作为子串的头. 若S[j+1]可以作为子串的头,则以S[i]结尾的符合条件的子串个数是i-j. 做法:单调队列的思想,不多解释,

HDU 4374 One hundred layer(单调队列优化dp)

题意:有一个n*m的矩阵,每格有一个分数,一个人站在(1,x)位置,在每一行中,他只能朝一个方向走(向左或向右),且最多走t步,问走到最后第n行得到的最大分数. 思路:不难想到状态转移方程dp[i][j] = max(dp[i-1][k]+sum[i][j]-sum[i][k-1]),(k<j) 移项得 dp[i][j]-sum[i][j] = max(dp[i-1][k] - sum[i][k-1]); 方程右侧与i,j无关,所以可以用单调队列维护max(dp[i-1][k] - sum[i]