【NOIP数据结构专项】单调队列单调栈
【FZYZ P1280 】【NOIP福建夏令营】矩形覆盖
Description
有N个矩形,矩形的底边边长为1,且均在X轴上,高度给出,第i个矩形的高为h[i],求最少需要几个矩形才能覆盖这个图形。
例如h = [3, 2, 4, 2]的图形如下:
容易发现,只需要3个矩形就能覆盖这个图形。
Input Format
第一行一个整数N。接下来1行包含N个正整数,为h[i]。
Output Format
输出一个整数表示最少需要几个矩形能覆盖这个图形。
Sample Input
10
2 3 2 4 2 1 3 4 3 2
Sample Output
7
Hint
对于所有数据,N<=100000,h[i] <= 100。
对于部分数据,N<=10;
对于部分数据,N<=100;
对于部分数据,N<=1000;
对于部分数据,h[i] <= 10;
题解
显然,若存在一个矩形的高度为x,则必然存在一个覆盖的矩形,其上边界高度为x.
所以,若所有h[i]各不相同,就要用N个矩形才能覆盖这个图形.
如果答案小于N,那么必然存在i,j(1<=i<j<=N),使得h[i]=h[j],且对任意k满足i<k<j,有h[k]>=h[i]且h[k]>=h[j](否则该覆盖矩形会超出图形的范围).
单调栈维护严格上升序列即可
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std; int n,ans;
int h[];
stack<int> q; int main()
{
int i,j;
scanf("%d",&n);
ans=n;
for(i=;i<=n;i++) scanf("%d",&h[i]);
q.push(h[]);
for(i=;i<=n;i++)
{
while(!q.empty()&&q.top()>=h[i])
{
if(q.top()==h[i]) ans--;
q.pop();
}
q.push(h[i]);
}
printf("%d",ans);
return ;
}
【洛谷P1901 】发射站
http://www.luogu.org/problem/show?pid=1901
题目描述
某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 Hi,并能向两边(当 然两端的只能向一边)同时发射能量值为 Vi 的能量,并且发出的能量只被两边最近的且比 它高的发射站接收。
显然,每个发射站发来的能量有可能被 0 或 1 或 2 个其他发射站所接受,特别是为了安 全,每个发射站接收到的能量总和是我们很关心的问题。由于数据很多,现只需要你帮忙计 算出接收最多能量的发射站接收的能量是多少。
输入格式
第 1 行:一个整数 N;
第 2 到 N+1 行:第 i+1 行有两个整数 Hi 和 Vi,表示第 i 个人发射站的高度和发射的能量值。
输出格式
输出仅一行,表示接收最多能量的发射站接收到的能量值,答案不超过 longint。
输入样例:
3
4 2
3 5
6 10
输出样例:
7
数据规模
对于 40%的数据,1<=N<=5000;1<=Hi<=100000;1<=Vi<=10000;
对于 70%的数据,1<=N<=100000;1<=Hi<=2,000,000,000;1<=Vi<=10000;
对于 100%的数据,1<=N<=1000000;1<=Hi<=2,000,000,000;1<=Vi<=10000。
题解
单调栈维护找出向左(右)边的第一个比自己大的数。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std; long long h[],p[],sum[];
struct hh{int l,r;};
hh f[];
long long ans;
int n,cnt;
stack<int> s; int main()
{
int i,j;
scanf("%d",&n);
for(i=;i<=n;i++)
scanf("%lld%lld",&h[i],&p[i]);
s.push();
for(i=;i<=n;++i)
{
while(!s.empty() && h[i]>h[s.top()]) f[s.top()].r=i,s.pop();
s.push(i);
}
while(!s.empty()) s.pop();
s.push(n);
for(i=n-;i>=;--i)
{
while(!s.empty() && h[i]>h[s.top()]) f[s.top()].l=i,s.pop();
s.push(i);
} for(i=;i<=n;i++){sum[f[i].l]+=p[i]; sum[f[i].r]+=p[i];}
for(i=;i<=n;i++) ans=max(ans,sum[i]);
printf("%lld",ans);
return ; }
【POJ2823 】【FZYZ P1561】滑动窗口
http://poj.org/problem?id=2823
Description
给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
你的任务是找出窗口在各位置时的max value,min value.
Input Format
第1行n,k,第2行为长度为n的数组
Output Format
2行,第1行每个位置的min value,第2行每个位置的max value
Sample Input
8 3
1 3 -1 -3 5 3 6 7
Sample Output
-1 -3 -3 -3 3 3
3 3 5 5 6 7
Hint
20%:n<=500;
50%:n<=100000;
100%:n<=1000000;
题解
双端单调队列维护
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int n,k;
int a[],maxx[],minn[];
int q[]; int main()
{
int i,j,head=,tail=;
scanf("%d%d",&n,&k);
for(i=;i<=n;i++) scanf("%d",&a[i]); head=;tail=;q[++tail]=;
for(i=;i<=k;i++)
{
while(head<=tail&&a[q[tail]]<a[i]) tail--;
q[++tail]=i;
}
maxx[]=a[q[head]];
for(i=k+;i<=n;i++)
{
while(head<=tail&&a[q[tail]]<a[i]) tail--;
while(head<=tail&&i-q[head]>=k) head++;
q[++tail]=i;
maxx[i-k+]=a[q[head]];
} head=;tail=;
q[++tail]=;
for(i=;i<=k;i++)
{
while(head<=tail&&a[q[tail]]>a[i]) tail--;
q[++tail]=i;
}
minn[]=a[q[head]];
for(i=k+;i<=n;i++)
{
while(head<=tail&&a[q[tail]]>a[i]) tail--;
while(head<=tail&&i-q[head]>=k) head++;
q[++tail]=i;
minn[i-k+]=a[q[head]];
}
for(i=;i<=n-k+;i++) printf("%d ",minn[i]);printf("\n");
for(i=;i<=n-k+;i++) printf("%d ",maxx[i]);
return ;
}
【ZLD NOIP模拟题】序列
【问题描述】
有一个长度为n的非负整数序列,每次操作可以选择相邻的两个数
,删去它们,然后在这个位置插入一个数
,此次操作的代价定义为
,求将这个序列长度变为1的最少代价。
【输入格式】
第一行为一个正整数n,表示序列的长度。
第二行有n个非负整数,表示这个序列。
【输出格式】
一行一个数,表示最少代价。
【输入输出样例】
seq.in |
seq.out |
3 1 2 3 |
5 |
【数据规模】
对于30%的数据,
对于50%的数据,
对于100%的数据,
题解
算法1:我们从左往右读入序列,用一个单调栈,当我们新加进去的数>栈顶时,那么便将栈顶的数拿去跟前一个或者当前的数合并(看哪个比较小),直到不满足这个条件,此时就把当前这个数塞入栈,最后注意一下栈中剩余的元素也是要合并的。
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
using namespace std;
int n;
long long ans;
int a[];
stack<int> q; int main()
{
int i,j,temp,in;
scanf("%d",&n);
for(i=;i<=n;i++) scanf("%d",&a[i]);
q.push();
for(i=;i<=n;i++)
{
if(!q.empty()&&q.top()>a[i])
{
q.push(a[i]);
continue;
}
while(!q.empty()&&q.top()<a[i])
{
q.pop();
if(a[i]>q.top()) ans+=(long long)q.top();
else ans+=(long long)a[i];
}
q.push(a[i]);
}
if(!q.empty()&&q.size()!=)
{
q.pop();
while(!q.empty())
{
if(q.size()==) goto hhh;
ans+=(long long)q.top();
q.pop();
}
}
hhh:;
printf("%lld",ans);
return ;
}
算法2:
标程做法。我们考虑相邻的两个数x,y,不妨设x>y,则我们先在x右端找一条最长的以y为左端点的区间,使区间内所有的数<=x。
然后呢我们将这些数合并起来,再与x合并,那么这个代价就是x了。
这下子做法就出来了,答案就是
代码略。
【NOIP数据结构专项】单调队列单调栈的更多相关文章
- 单调队列 && 单调栈
单调队列 && 单调栈 单调队列 维护某个滑动区间的min or max,可用于dp的优化 以维护min为例,采用STL双端队列实现 每次加入元素x前 先检查队首元素==滑动后要删除的 ...
- 联赛模拟测试18 A. 施工 单调队列(栈)优化DP
题目描述 分析 对于 \(Subtask\ 1\),可以写一个 \(n^3\) 的 \(DP\),\(f[i][j]\) 代表第 \(i\) 个建筑高度为 \(j\) 时的最小花费,随便转移即可 时间 ...
- 数据结构录 之 单调队列&单调栈。
队列和栈是很常见的应用,大部分算法中都能见到他们的影子. 而单纯的队列和栈经常不能满足需求,所以需要一些很神奇的队列和栈的扩展. 其中最出名的应该是优先队列吧我觉得,然后还有两种比较小众的扩展就是单调 ...
- 数据结构录 之 单调队列&单调栈。(转)
http://www.cnblogs.com/whywhy/p/5066306.html 队列和栈是很常见的应用,大部分算法中都能见到他们的影子. 而单纯的队列和栈经常不能满足需求,所以需要一些很神奇 ...
- 小Z爱序列(NOIP信(sang)心(bin)赛)From FallDream(粗制单调队列&单调栈的算法解析)
原题: 小Z最擅长解决序列问题啦,什么最长公共上升然后下降然后上升的子序列,小Z都是轻松解决的呢. 但是小Z不擅长出序列问题啊,所以它给了你一道签到题. 给定一个n个数的序列ai,你要求出满足下述条件 ...
- 单调队列&单调栈
单调队列 例题: Poj 2823给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数.数列长度:N<=106,m<=N 对于单调队列,我们这样子来定义: 1.维护区间最值 2 ...
- 大视野 1012: [JSOI2008]最大数maxnumber(线段树/ 树状数组/ 单调队列/ 单调栈/ rmq)
1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 9851 Solved: 4318[Submi ...
- POJ 3494 Largest Submatrix of All 1’s 单调队列||单调栈
POJ 3494 Largest Submatrix of All 1’s Description Given a m-by-n (0,1)-matrix, of all its submatrice ...
- 单调队列&单调栈归纳
单调队列 求长度为M的区间内的最大(小)值 单调队列的基本操作,也就是经典的滑动窗口问题. 求长度为M的区间内最大值和最小值的最大差值 两个单调队列,求出长度为M的区间最大最小值的数组,分别求最大最小 ...
随机推荐
- Handler, AsyncTask用法简单示例
package com.jim.testapp; import android.app.Activity; import android.os.AsyncTask; import android.os ...
- 智能算法之Matlab实现(1)——遗传算法(1)
遗传算法的过程在这里先不介绍了,可能在接下来的几篇文章会介绍,这里介绍些实用的. (1)Sheffield遗传算法工具箱的安装 我共享了下修改过文件名和后缀名的原版工具箱,地址为:http://pan ...
- poj3308 最小割
因为行可以了,那列就不行,所以根据行列建立最小割模型. 然后这题精妙之处在于把乘法取对数后转化为加法,瞬间就简单了. 保证精度,C++AC ,16MS G++WA. #include<stdio ...
- oracle表复杂查询--多表查询
多表查询是指基于两个和两个以上的表或是视图的查询,在实际应用中,查询单个表可能不能满足你的要求,如显示sales部门位置和其员工的姓名,这种情况下需要使用到dept表和emp表. select ...
- toString和valueOf使得对象访问时显示一个特定格式的字符串,但是可以进行数字运算
作用 toString()的作用是返回一个反映这个对象的字符串; valueOf()的作用是返回它相应的原始值; 异同点 共同点:在 JavaScript 中,toString()方法和valueOf ...
- 在 Linux 启动或重启时执行命令与脚本
有时可能会需要在重启时或者每次系统启动时运行某些命令或者脚本.我们要怎样做呢?本文中我们就对此进行讨论. 我们会用两种方法来描述如何在 CentOS/RHEL 以及 Ubuntu 系统上做到重启或者系 ...
- SP2-0642: SQL*Plus internal error state 2130, context 0:0:0
..experience, Working case SP2-0642: SQL*Plus internal error state 2130, context 0:0:0 2016-10-09 没有 ...
- C++与JAVA代码实现CRC-16/MODBUS算法,且与 http://www.ip33.com/crc.html 进行结果验证
CRC-16/MODBUS的多项式为:x16+x15+x2+1(8005),宽度为16.运算时,首先将一个16位的寄存器预置为11111111 11111111,然后连续把数据帧中的每个字节中的8位与 ...
- GMTC2019|闲鱼-基于Flutter的架构演进与创新
2012年应届毕业加入阿里巴巴,主导了闲鱼基于Flutter的新混合架构,同时推进了Flutter在闲鱼各业务线的落地.未来将持续关注终端技术的演变及趋势 Flutter的优势与挑战 Flutter是 ...
- Xcode4.2 本地化 总结
1 xcode4.2,如果是简体中文,把国际化的文件放到zh-Hans.lproj中就显示正常了.如果放到zh.lproj中就不可以 2 字符串 1)在项目的"supporting file ...