zoukankan      html  css  js  c++  java
  • 栈和队列小刷

    栈和队列

    bzoj1012// JSOI2008 最大数 maxnumber

    详见博客:https://www.cnblogs.com/tyner/p/11267630.html

    bzoj2086 [Poi2010]Blocks

    https://www.luogu.org/problem/P3503

    题意

    给出 N 个正整数 a[1...N],再给出一个正整数 k,现在可以进行
    如下操作:
    每次选择一个大于 k 的正整数 a[i],将 a[i] 减去 1,选择a[i - 1] 或 a[i + 1] 中的一个加上 1。
    经过一定次数的操作后,问最大能够选出多长的一个连续子序列,使得这个子序列的每个数都不小于 k。
    总共给出 M 次询问,每次询问给出的 k 不同,你需要分别回答。
    (N <= 1000000)(M <= 50)(k <= (10^9))
    保证答案都在 long long 以内

    分析

    首先要明确一下,这里的M<=50,说明它需要O(n)的算法(不然它不就只让你修改一次,然后O(nlogn)水掉嘛....)(老师分析的,自己没往这儿想....以后注意一下吧)

    其次:要求子序列的每个数都>=k,结合题目中的操作,即需要子序列的平均数>=k。(只要它的平均数>=k, 然后你把较大的几个数-1,然后往较小的数那里传,这样它一定阔以使每个数>=k的这个我又没想出来....)

    然后,让平均数>=k,只需把每个数都减上k,使他们的和>=0即可(这个很容易想到...吧),快速维护一个区间和就用个前缀和sum就行了。

    重点: 当i < j && sum[i] <= sum[j]时, i 做为左边界一定是比 j 更优的。所以我们维护一个sum单调递减的栈,在用一个指针n->0扫一遍,每次不断弹栈(不用从头重新找),更新答案

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int MAXN = 1000000+99;
    
    int n,m;
    ll a[MAXN], sum[MAXN];
    int q[MAXN];
    ll k;
    
    void solve(ll k) {
    	int ans = 0;
    	for(int i = 1; i <= n; i++) sum[i] = sum[i-1]+a[i]-k;
    	int l = 0, r = 0;
    	for(int i = 1; i <= n; i++) 
    		if(sum[q[r]] > sum[i]) q[++r] = i;//l更优,所以这样做 
    	for(int i = n, j = r; i >= 1; i--) {//保证i在右边 
    		while(j>l && sum[i]-sum[q[j-1]] >= 0) --j;//注意判非空 
    		//因为要把j左移一,所以比较的是q[j-1]的sum和i的 
    		ans = max(ans, i-q[j]);
    	}
    	printf("%d",ans);
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i = 1; i <= n; i++) scanf("%lld",&a[i]);
    	for(int i = 1; i <= m; i++) {
    		scanf("%lld",&k);
    		solve(k);
    		if(i != m) printf(" ");
    	}
    }
    

    [JLOI2012] 树

    题意

    给定一个值 S 和一棵树。在树的每个节点有一个正整数,问有多少条路径的节点总和为 S 。路径中节点的深度必须是升序的。
    假设节点 1 是根节点,根的深度是 0,它的儿子节点的深度为1。路径不必一定从根节点开始。

    分析

    (不知道这题的单调队列做法,看到题解说可以用前缀和,然后就...这样了)

    因为题目中限制深度必须升序,所以就是dfs到底的一条链,且每个节点都有一个正整数,所以他们的前缀和都不同,所以我们只需边dfs边往set里加sum[i], 每加入一个就在set里面找有没有值等于sum[i]-s, 统计答案即可。

    注意dfs结束时erase当前节点的sum

    #include<cstdio>
    #include<set>
    #include<algorithm>
    using namespace std;
    const int MAXN = 100000+99;
    const int MAXM = MAXN<<1;
    
    int n,S,ans;
    int sum[MAXN];
    set <int> s;
    
    int head[MAXN], cnt;
    struct seg{
    	int y, next;
    }e[MAXM];
    void add_edge(int x, int y) {
    	e[++cnt].y = y;
    	e[cnt].next = head[x];
    	head[x] = cnt;
    }
    
    void dfs(int x, int fa) {
    	sum[x] += sum[fa]; 
    	s.insert(sum[x]);
    	if(s.count(sum[x]-S)) ans++;
    	for(int i = head[x]; i; i = e[i].next) 
    		if(e[i].y != fa) 
    			dfs(e[i].y, x);
    	s.erase(sum[x]);//记着清除 
    }
    
    int main() {
    	scanf("%d%d",&n,&S);
    	for(int i = 1; i <= n; i++) scanf("%d",&sum[i]);
    	int x, y;
    	for(int i = 1; i < n; i++) {
    		scanf("%d%d",&x,&y);
    		add_edge(x, y);
    		add_edge(y, x);
    	}
    	s.insert(0);//有的恰为s
    	dfs(1, 0);
    	printf("%d",ans);
    }
    
  • 相关阅读:
    C语言之指针基础概念
    Android之常用功能代码
    Android之ImageButton控件基础操作
    BZOJ1079或洛谷2476 [SCOI2008]着色方案
    HDOJ2870 Largest Submatrix
    BZOJ1855或洛谷2569 [SCOI2010]股票交易
    BZOJ1233 [Usaco2009Open]干草堆tower
    HDOJ4261 Estimation
    POJ3254或洛谷1879 Corn Fields
    POJ1037 A Decorative Fence
  • 原文地址:https://www.cnblogs.com/tyner/p/11379435.html
Copyright © 2011-2022 走看看