HDU 4193 Non-negative Partial Sums(想法题,单调队列)

HDU 4193

题意:给n个数字组成的序列(n <= 10^6),求该序列的循环同构序列中,有多少个序列的任意前i项和均大于或等于0.

思路:

这题看到数据规模觉得只能用最多O(nlogn)的算法,然后想到了之前刚做过的有关最小表示法的题,但还没证明出一个做这题有效的算法出来。

后来看过题解,发现用的最多的方法是单调队列,然而我对这个知识点知之甚少orz

/*科普君:from单调队列

单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。

以单调不减队列为例:队列内的元素(e1,e2,e3...en)存在(e1<=e2<=e3<=...<=en)的关系,所以队首元素e1一定是最小的元素。与优先队列不同的是,当有一个新的元素e入队时,先要将队尾的所有大于e的元素弹出,以保证单调性,再让元素e入队尾。

例如这样一组数(1,3,2,1,5,6),进入单调不减队列的过程如下:

1入队,得到队列(1);

3入队,得到队列(1,3);

2入队,这时,队尾的的元素3>2,将3从队尾弹出,新的队尾元素1<2,不用弹出,将2入队,得到队列(1,2);

1入队,2>1,将2从队尾弹出,得到队列(1,1);

5入队,得到队列(1,1,5);

6入队,得到队列(1,1,5,6)*/

利用单调队列的解题思路是://参考:http://blog.csdn.net/code_pang/article/details/14228969

首先用循环序列的一般处理方法,将数列复制并接在一起。

然后处理出来sum,sum[i]表示a[1]~a[i]的和。

设S[i]为长度为n的子序列前i项之和,假设子序列的最后一个数的下标为就j,那么j-n+1 <= i <= j,S[i] = A[j-n+1] + A[j-n] + … + A[i],.

Sum[i]和S[i]的转化关系为:当前子序列的末尾数的下标为j,S [i] =Sum[i] – Sum[j-n]。

题中要找满足所有S(i) >= 0条件的n长子序列,所以只需要找出最小的S(i),如果它的值都大于等于0的话,该序列就满足条件,ans++即可。

使用单调递增队列来寻找最小的S[i]。

其他解题思路://参考:http://blog.csdn.net/ice_crazy/article/details/9697885

先考虑如果整个序列和sum<0,那么肯定ans=0;

再考虑一个性质,如果当前的长度为n的序列满足题中条件,那么我们可以只将最后的元素放到首位,如果移动前序列满足条件,则此次移动后得到的序列是否满足条件便由此元素决定。

如果这个元素 >= 0,那么这次移动得到的新队列同样满足题中的条件,ans++;

如果这个元素 < 0,则再次移动并累加移动元素值,直到某次移动后这个累计

值 >= 0,此时ans可以+1,并且要把这个累计值清零。

当移动后序列又成为原合法序列时,结束移动。

code:(后一种解题思路)

/*
* @author Novicer
* language : C++/C
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

const int maxn = 1000000 + 5;
int a[maxn];

int main(){
	int n;
	while(cin >> n && n){
		int cnt = 0;
		int total = 0;
		for(int i = 1 ; i <= n ; i++){
			scanf("%d",&a[i]);
			total += a[i];
		}
		if(total < 0){
			cout << 0 << endl;
			continue;
		}
		else{
			int l = 0;
			int pos = n;
			int ans = 0;
			int sum = 0;
			while(l <= pos){
				sum += a[l];
				l++;
				while(sum < 0){
					sum += a[pos];
					pos--;
				}
			}
//			cout << l << endl;
//			cout << pos << endl;
			int tmp = 0;
			while(pos >= 1){
				if(tmp >= 0) ans ++;
				if(tmp < 0)	tmp += a[pos];
				else if(a[pos] < 0) tmp = a[pos];
				pos--;
			}
			cout << ans << endl;
		}
	}
	return 0;
}

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

时间: 2024-12-25 06:22:17

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

hdu 6444 网络赛 Neko&#39;s loop(单调队列 + 裴蜀定理)题解

题意:有编号为0~n-1的n个游戏,每个活动都有一个价值(可为负),给你m,s和k,你可以从任意一个编号开始玩,但是下一个游戏必须是编号为(i + k)%n的游戏,你最多能玩m次游戏,问你如果最后你手里要有s的价值,那么你至少一开始要有多少价值. 思路:由裴蜀定理可以知道,如果有n个值首尾相连,间隔为k地走,那么最后会有一个循环节,这样的循环节一共有gcd(n, k)个,每个循环节长度n / gcd(n, k)个.所以我们只要找出所有循环节,并且把每个循环节的最大价值算出来就行了.对于每个循环节

hdu 5386 Cover(暴力求解+想法题)

题意: 有两种操作: 操作L x y,把当前x,这一列全部置为y 操作H x y,把当前,这一行全部置为y. 现在给你n?n的初始矩阵,以及n?n的目标矩阵 现在给你m种操作(由以上两种操作构成),问怎么排序这m种操作,才能使得,初始矩阵,经由排序后的操作,构成目标矩阵. 输出排序方案. 解析: 逆向思维, 枚举每个操作,然后判断该操作是不是最后一个操作.(就像撕胶布一样,一条一条的剥离) 判断是否是最后一个操作方法就是: 除去已经用过的点,如果一排都等于当前操作的颜色,那就是最后一个操作.然后

hdu 5414 CRB and String(想法题)

题意: 给你两个字符串s和t,你可以在字符串s中任意选一个字符c,在该字符c后插入一个字符d(d!=c),问经过多次此操作,能否将字符串s转化成字符串t. 解析: 不要想太复杂了,分情况讨论清楚就好了. 1. 如果|s|>|t|,那么无论怎么组合都是无法构成t的. 2. 如果s[0]!=t[0],无论怎么组合,也都是无法构成t的. 3. 以上两种情况比较好考虑,然后找两个串的最长公共前缀. 如果s的最长公共前缀等于|t|则表明两个字符串完全相同,这种看情况可以构造出t,因为上面已经排除了|s|>

hdu 5090 Game with Pearls (额,, 想法题吧 / 二分图最大匹配也可做)

题意: 给你N个数,a1,,,,an.代表第i个管子里有ai个珍珠. 规定只能往每根管里增加k的倍数个珍珠. 如果存在一套操作,操作完毕后可以得到1~N的一个排列,则Jerry赢,否则Tom赢. 问谁赢. 思路: 将a1...an从小到大排序,可知道每根管里的数只能增不能减.将最后的1...N中的每个数一定是由小于等于它的数加上若干个K得到来的. 额..直接看代码吧 代码: int a[1005]; int m,n,k; int main(){ //freopen("test.in",

HDU 4123 Bob’s Race 树的直径+单调队列

题意: 给定n个点的带边权树Q个询问. 下面n-1行给出树 下面Q行每行一个数字表示询问. 首先求出dp[N] :dp[i]表示i点距离树上最远点的距离 询问u, 表示求出 dp 数组中最长的连续序列使得序列中最大值-最小值 <= u,输出这个序列的长度. 思路: 求dp数组就是求个树的直径然后dfs一下. 对于每个询问,可以用一个单调队列维护一下.O(n)的回答. #include <cstdio> #include <cstring> #include <strin

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了几次. 最近少刷水题,而一直都是每天一

HUD 3706 单调队列简单题

Problem Description Give you three integers n, A and B. Then we define Si = Ai mod B and Ti = Min{ Sk | i-A <= k <= i, k >= 1} Your task is to calculate the product of Ti (1 <= i <= n) mod B. 不描述题意了,三行英文挺明了的,今天刚学单调队列,自己模拟一下过了这题 单调队列 1,永远保持队

HDU 2410 Barbara Bennett&#39;s Wild Numbers (想法题)

题目链接:HDU 2410 Barbara Bennett's Wild Numbers 题意:给出两串数w,s(长度相同),第一串中有"?",问"?"取的值使w对应的数大于s对应的数 的最大方案数. 思路:W,S一一对应比较: 遇到第一个'?'之前比较情况 1.w[i]<s[i] 方案数0种:break: 2.w[i]>s[i] break.之后有n个''?' 方案数就有10的n次方种. 3.w[i]=s[i] 继续比较,重复1.2两个条件. 遇到'?

HDU 2410 Barbara Bennett&amp;#39;s Wild Numbers (想法题)

题目链接:HDU 2410 Barbara Bennett's Wild Numbers 题意:给出两串数w,s(长度同样),第一串中有"?",问"?"取的值使w相应的数大于s相应的数 的最慷慨案数. 思路:W,S一一相应比較: 遇到第一个'?'之前比較情况 1.w[i]<s[i] 方案数0种:break: 2.w[i]>s[i] break. 之后有n个''?' 方案数就有10的n次方种. 3.w[i]=s[i] 继续比較.反复1.2两个条件. 遇到'