[b][b][b][b][size=large][size=medium]一、 什么是单调(双端)队列
单调队列,顾名思义,就是一个元素单调的队列,那么就能保证队首的元素是最小(最大)的,从而满足动态规划的最优性问题的需求。
单调队列,又名双端队列。双端队列,就是说它不同于一般的队列只能在队首删除、队尾插入,它能够在队首、队尾同时进行删除。
【单调队列的性质】
一般,在动态规划的过程中,单调队列中每个元素一般存储的是两个值:
1、在原数列中的位置(下标)
2、 他在动态规划中的状态值
而单调队列则保证这两个值同时单调。
从以上看,单调队列的元素最好用一个类来放,不这样的话,就要开两个数组。。。
单调队列:单调队列 即保持队列中的元素单调递增(或递减)的这样一个队列,可以从两头删除,只能从队尾插入。单调队列的具体作用在于,由于保持队列中的元素满足单调性,对手元素便是极小值(极大值)了。
http://poj.org/problem?id=2823
//poj-2823--单调队列
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX = 1000001;
//两个单调队列
int dq1[MAX]; //一个存单调递增
int dq2[MAX]; //一个存单调递减
int a[MAX];
inline bool scan_d(int &num) // 这个就是 加速的 关键了
{
char in;bool IsN=false;
in=getchar();
if(in==EOF)
return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-') { IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
{
num*=10,num+=in-'0';
}
if(IsN)
num=-num;
return true;
}
int main(void)
{
int i,n,k,front1,front2,tail1,tail2,start,ans;
while(scanf("%d %d",&n,&k)!=EOF)
{
for(i = 0 ; i < n ; ++i)
scan_d(a[i]);
front1 = 0, tail1 = -1;
front2 = 0, tail2 = -1;
ans = start = 0;
for(i = 0 ; i < k ; ++i)
{
while(front1 <= tail1 && a[ dq1[tail1] ] <= a[i]) //当前元素大于单调递增队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素大于当前当前元素的时候,将当前元素插入队尾
--tail1;
dq1[ ++tail1 ] = i; //只需要记录下标即可
while(front2 <= tail2 && a[ dq2[tail2] ] >= a[i]) //当前元素小于单调递减队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素小于当前当前元素的时候,将当前元素插入队尾
--tail2;
dq2[ ++tail2 ] = i; //只需要记录下标即可
}
printf("%d ",a[ dq2[ front2 ] ]);
for( ; i < n ; ++i)
{
while(front2 <= tail2 && a[ dq2[tail2] ] >= a[i])
--tail2;
dq2[ ++tail2 ] = i;
while(dq2[ front2 ] <= i - k)
++front2;
if(i != n-1)
printf("%d ",a[ dq2[ front2 ] ]);
}
printf("%d\n",a[ dq2[ front2 ] ]);
//输出最大值
printf("%d ",a[ dq1[ front1 ] ]);
for(i=k ; i < n ; ++i)
{
while(front1 <= tail1 && a[ dq1[tail1] ] <= a[i])
--tail1;
dq1[ ++tail1 ] = i;
while(dq1[ front1 ] <= i - k)
++front1;
if(i != n-1)
printf("%d ",a[ dq1[ front1 ] ]);
}
printf("%d\n",a[ dq1[ front1 ] ]);
}
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=3530 Subsequence
/*
题意:给出一个序列,求最长的连续子序列,使得 M<=Max-Min<=K
n <= 10^5
依次枚举剩下的N-1个元素,并且将当前未入队的第一个元素和队尾元素比较,当且仅当队列为非空并且队尾元素的值小于当前未入队的元素时,
将队尾元素删除(也就是队尾指针-1),因为当前的元素比队尾元素大,所以在区间内队尾元素不会是最大值了。
重复这个过程直到队列空或者队尾元素比当前元素大,
*/
#include<iostream>
#include<cstdio>
using namespace std;
const int MAX = 100001;
//两个单调队列
int dq1[MAX]; //一个存单调递增
int dq2[MAX]; //一个存单调递减
int a[MAX];
inline bool scan_d(int &num) // 这个就是 加速的 关键了
{
char in;bool IsN=false;
in=getchar();
if(in==EOF)
return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-') { IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
{
num*=10,num+=in-'0';
}
if(IsN)
num=-num;
return true;
}
int main(void)
{
int i,n,m,k,front1,front2,tail1,tail2,start,ans;
while(scanf("%d %d %d",&n,&m,&k) != EOF)
{
for(i = 0 ; i < n ; ++i)
scan_d(a[i]);
front1 = 0, tail1 = -1;
front2 = 0, tail2 = -1;
ans = start = 0;
for(i = 0 ; i < n ; ++i)
{
while(front1 <= tail1 && a[ dq1[tail1] ] <= a[i]) //当前元素大于单调递增队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素大于当前当前元素的时候,将当前元素插入队尾
--tail1;
dq1[ ++tail1 ] = i; //只需要记录下标即可
while(front2 <= tail2 && a[ dq2[tail2] ] >= a[i]) //当前元素小于单调递减队列的队尾元素的时候,队尾的元素依次弹出队列,直到队尾元素小于当前当前元素的时候,将当前元素插入队尾
--tail2;
dq2[ ++tail2 ] = i; //只需要记录下标即可
/*
Max - Min 为两个队列的队首之差
while(Max-Min>K) 看哪个的队首元素比较靠前,就把谁往后移动
*/
while(a[ dq1[front1] ] - a[ dq2[front2] ] > k)
{
if(dq1[front1] < dq2[front2] )
{
start = dq1[front1] + 1;
++front1;
}
else
{
start = dq2[front2] + 1;
++front2;
}
}
if(a[ dq1[front1] ] - a[ dq2[front2] ] >= m)
{
if(i - start +1 > ans)
ans = i - start + 1;
}
}
printf("%d\n",ans);
}
return 0;
}
分享到:
相关推荐
当我们需要求解`dp[i]=min{f(k)}`或`dp[i]=max{f(k)}`这类问题,其中`f(k)`是关于`k`的函数,而`k`的范围与`i`有关时,单调队列优化能起到重要作用。单调队列用于维护一个单调递增或递减的序列,允许在两端进行元素...
- 单调队列适用于那些具有单调性的动态规划问题,通过维护一个单调队列,可以在较短时间内找到所需的最大值或最小值,从而提高算法的效率。 ##### 二、一些简单的例子 **【例一】生产产品 Vijos1243** - **题目...
模版中提到DAG上的动态规划、分组背包、单调队列、状态压缩TSP等问题。这些都表明动态规划在处理各种最优化问题中的广泛适用性,如图上路径问题、背包问题、状态压缩问题等。 6. RMQ(Range Minimum Query) RMQ是...
* 动态规划:15 题以上,包括最大子串和、最长公共子序列、最长单调递增子序列等 * 算法设计与分析:学会分析与计算复杂程序的时间复杂度、使用栈与队列等线性存储结构、分治策略 * 排序算法:归并排序、快速排序、...
2. 队列、栈、优先队列:线性结构的应用广泛,如Fibonacci堆、单调栈等。 3. 哈希表:解决查找和映射问题,解决冲突的方法,如链地址法、开放寻址法。 4. 字符串结构:Trie树、后缀数组、后缀自动机等。 三、编程...
8. **堆栈和队列的变种**,如单调栈(维护一个递增或递减的栈)和单调队列(保持队列中的元素按一定顺序),在求解区间最大值、最小值等问题时非常有用。 9. **动态规划**:通过将大问题分解为子问题来求解,常涉及...
### 浙大ACM代码模板知识点解析 #### 一、几何 ##### 1.1 注意事项 - **坐标精度处理**:在处理几何问题时,由于计算机存储浮点数的精度限制,通常需要采取特殊的方式来处理小数点后的位数问题,避免因精度误差而...
- **解决方案**:利用单调队列来维护窗口内元素的单调递增序列。当窗口向右移动时,队列头部元素即为当前窗口的最小值。 - **时间复杂度**:O(n)。 4. **例4:程序复杂度分析** - **问题描述**:给定一个只包含...
- **单调队列**:维护一个队列,使得队列中的元素保持单调递增或递减。 - **凸完全单调性**:利用凸函数的性质来优化动态规划问题。 - **树型动规**:在树形结构上的动态规划。 - **多叉转二叉**:将多叉树转化为...
单调队列或者单调栈可以用来加速某些动态规划问题的状态更新过程,例如在处理最值问题时,如果当前状态只与前几个状态有关,且存在单调性,那么可以使用这些数据结构来快速找到需要的前几个状态,从而提升算法效率。...
- **堆**:用于优先队列和最值问题。 - **Trie 树**:高效存储和查找字符串,分为静态建树和动态建树。 4. **简单搜索**: - **深度优先搜索(DFS)**:poj2488、poj3083 等。 - **广度优先搜索(BFS)**:poj...
1. 单调队列:优化动态规划中的单调性问题。 2. 线段树:用于处理区间更新和查询的动态数据结构,可扩展为二维线段树。 3. 树状数组:一种轻量级的数据结构,能快速完成区间加法和查询。 4. 并查集:处理不相交集合...
- **最长公共单调子序列**:寻找两个序列中最长的单调递增或递减的公共子序列。 #### 十四、其它 - **大数(只能处理正数)**:用于处理超出普通整数范围的大数运算。 - **分数**:分数类的设计及其运算。 - **矩阵**...
3. 计算方法:二分法解决单调函数问题,如poj3273、poj3258等。 七、计算几何学 1. 几何公式:如点、线、面的关系。 2. 叉积和点积:用于判断线段相交和距离计算,如poj2031、poj1039。 3. 多边形:求面积和相关...
* 单调队列优化:包括单调队列、队列优化等 * 概率 DP:包括概率计算、期望值计算等 四、NOIP 动态规划总结 * 动态规划的应用场景 * 动态规划的算法设计 * 动态规划的优缺点 五、 ACM 动态规划总结 * ACM 动态...
POJ3709题目的“K-匿名序列”问题,进一步展示了如何应用队列优化动态规划模型,特别是当动态规划模型满足凸单调性时。在这个问题中,玩家需要将一个序列{An}修改为新的序列{Bn},使得序列非递减,并且每个元素都有...
4. **滑动窗口最大值/最小值**:在数组或序列中,找到固定大小窗口内的最大值或最小值,常使用双指针或单调栈解决。 ### 第十四周:组合数学与概率论 1. **排列组合**:学习排列、组合、二项式定理,用于解决各种...
【专辑】单调队列+斜率优化的DP 01背包问题 acm动态规划总结 PKU——DP专辑 背包之01 POJ 动态规划总结 背包之01背包、完全背包、多重背包详解 Dynamic+Programming 典型的动态规划,用递归下的记忆化搜索来实现 ...
- 单调队列:用于维护当前价格区间内的最低价。 - 贪心算法:基于当前的最佳买入价格作出决策。 #### 9. Number Triangles (数字三角形) - **描述**:在给定的数字三角形中寻找路径,使得路径上的数字之和最大。...