zoukankan      html  css  js  c++  java
  • 单调队列 单调栈总结(转)

    http://blog.csdn.net/gg_gogoing/article/details/40312827

    单调队列单调栈应用范围:

    求一串数最长不降子序列,维护一个单调不减栈。

    1. 自此元素最远的不大于(不小于)本身的数

    单调栈与单调队列很相似,首先栈是后进先出的,单调性指的是严格的递增或者递减。

    单调栈有以下两个性质:

    1、若是单调递增栈,则从栈顶到栈底的元素是严格递增的。若是单调递减栈,则从栈顶到栈底的元素是严格递减的。

    2、越靠近栈顶的元素越后进栈。

    单调栈与单调队列不同的地方在于栈只能在栈顶操作,因此一般在应用单调栈的地方不限定它的大小,否则会造成元素无法进栈。

    元素进栈过程:对于单调递增栈,若当前进栈元素为e,从栈顶开始遍历元素,把小于e或者等于e的元素弹出栈,直接遇到一个大于e的元素或者栈为空为止,然后再把e压入栈中。对于单调递减栈,则每次弹出的是大于e或者等于e的元素。

    一个单调递增栈的例子:

    进栈元素分别为3,4,2,6,4,5,2,3

    3进栈:(3)

    3出栈,4进栈:(4)

    2进栈:(4,2)

    2出栈,4出栈,6进栈:(6)

    4进栈:(6,4)

    4出栈,5进栈:(6,5)

    2进栈:(6,5,2)

    2出栈,3进栈:(6,5,3)

    以上左端为栈底,右端为栈顶。

    队列是一种先进先出的数据结构,单调指的是数学中的单调性,包括严格的递增或者递减。

    单调队列指的就是严格符合单调性的队列,它有两个性质:

    1、对于单调递增队列,从队头到队尾的元素在某种比较标准下是严格递增的,比如q(1, 2, 3, 4, 5)。对于单调递减队列,从队头到队尾的元素在某种比较标准下是严格递减的,比如q(5, 4, 3, 2, 1)。

    2、排在前面的元素必定比排在后面的元素先进队。

    这两个性质都很简单,但不能为了符合性质2而破坏性质1,若当前队列是q(1, 2, 3, 5),下一个进队元素是4,则不能把4放到5的前面,变成q(1, 2, 3, 4, 5),这样就不符合性质2了。

    元素的入队方法:对于单调递增队列,设当前准备入队的元素为e,从队尾开始把队列中的元素逐个与e对比,把比e大或者与e相等的元素逐个删除,直到遇到一个比e小的元素或者队列为空为止,然后把当前元素e插入到队尾。对于单调递减队列也是同样道理,只不过从队尾删除的是比e小或者与e相等的元素。

    若队列有大小限制,则每次插入新元素的时候,需要从队头开始弹出元素,直到队列至少有一个空间留给当前元素。

    以下是一个单调递增队列的例子:

    队列大小不能超过3,入队元素依次为3,2,8,4,5,7,6,4

    3入队:(3)

    3从队尾出队,2入队:(2)

    8入队:(2,8)

    8从队尾出队,4入队:(2,4)

    5入队:(2,4,5)

    2从队头出队,7入队:(4,5,7)

    7从队尾出队,6入队:(4,5,6)

    6从队尾出队,5从队尾出队,4从队尾出队,4入队:(4)

    以上左端为队头,右端为队尾。从队尾出队是为了符合性质2,从队头出队是为了符合队列的大小限制。

    ==========================================================================

    2015.5.17更新

    题目训练:点击打开链接

    这个和优先队列不同在于当你选择最优后,移除的时候要考虑位置的因素。这样优先队列就搞不定了

    有一个题没拉进去,poj 3017 参考:点击打开链接  点击打开链接  点击打开链接

    递推公式很容易得到,分析数据特点发现f[]这个dp是递增的,每次的决策点就是单调队列里面的各个元素,而且dp[i] = min(dp[p1]+p2) 单调队列每次去掉不满足M的元素即可。

     1 #include<cstdio>
     2 #include<set>
     3 using namespace std;
     4 int D[100010],a[100010],L,R,N,low;
     5 long long M,sum,f[100010],temp;
     6 multiset<int> tree;
     7 int main(){
     8     scanf("%d%I64d",&N,&M);
     9     for (int i=1;i<=N;i++)
    10         scanf("%d",&a[i]);
    11     L=0;R=-1;sum=0;low=1;
    12     bool flag=true;
    13     for (int i=1;i<=N;i++){
    14         sum+=a[i];
    15         while (sum>M) sum-=a[low++];
    16         if (low> i){
    17             L=0;R=-1;printf("-1");flag=false;break;
    18         }
    19         while (L<=R&&a[i]>=a[D[R]]) {
    20             if (R>L) tree.erase(f[D[R-1]]+a[D[R]]);
    21                 R--;
    22         }
    23         D[++R]=i;if (R>L) tree.insert(f[D[R-1]]+a[D[R]]);
    24         while (low>D[L]) {
    25             if (R>L) tree.erase(f[D[L]]+a[D[L+1]]);
    26             L++;
    27         }
    28         temp=*(tree.begin());f[i]=f[low-1]+a[D[L]];
    29         if (L<R&&temp<f[i]) f[i]=temp;
    30     }
    31     if (flag) printf("%I64d",f[N]);
    32     return 0;
    33 }
  • 相关阅读:
    编程中Visual Studio常用的快捷键
    解决博易博客后台文章管理页面无法显示分页的问题
    iReaper for WP7 顺利完工
    Visual Studio中web应用程序和网站区别
    SQL批处理
    SQL安全性
    实习之路之篇
    python 日志文件
    后端调用python遥感功能的方式
    C#使用系统的“显示桌面”功能(Shell.Application)
  • 原文地址:https://www.cnblogs.com/gongpixin/p/6757854.html
Copyright © 2011-2022 走看看