zoukankan      html  css  js  c++  java
  • 单调队列与单调栈(入门)

    这些知识总算啃掉了...

    重要的思路就是加入栈和队列时还要加入元素的坐标位置。

    使用单调栈可以找到元素向左遍历第一个比他小的元素,也可以找到元素向左遍历第一个比他大的元素。

    单调栈就简单点,只有栈顶可以操作,若要找到从左到右第一个比i大的数,就保证严格递减,这样如果到第一个比i大的数是i就会被弹出,总之就是找什么条件的数,第i个数被弹出栈的条件就是什么,建议手打栈,代码如下:

    n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++)
        {
            while(top>=1&&a[i]>=q[top].s) ans=ans+i-q[top--].id-1;
            q[++top].id=i;q[top].s=a[i]; 
        }
        for(int i=top;i>=1;i--) ans=ans+n-q[top--].id;

    单调队列除了tail需要更新,还需要更新head,也就是及时把不符合信息的head出队,、

    单调队列性质:

    • 1、维护区间最值
    • 2、去除冗杂状态 如上题,区间中的两个元素a[i],a[j](假设现在再求最大值)
      若 j>i且a[j]>=a[i] ,a[j]比a[i]还大而且还在后面(目前a[j]留在队列肯定比a[i]有用,因为你是往后推, 核心思想 !
    • 其中第二条对动态规划仍使用...

    与题目联系时,记得把要求的元素放在队头就行了.

    例:

    for(int i=1;i<=k;i++)
        {
            while(head<=tail&&q[tail].s>=a[i]) tail--;
            q[++tail].id=i,q[tail].s=a[i];
        }
        mn[++o]=q[head].s;
        for(int i=k+1;i<=n;i++)
        {
            while(head<=tail&&q[tail].s>=a[i]) tail--;
            q[++tail].id=i,q[tail].s=a[i];
            while(q[head].id<=i-k) head++;
            mn[++o]=q[head].s;
        }

    好,让我们来看这个题:

    题目很简单,求连续的长度范围在p到q的最大长度和...

    暴力吗?O(n2)...

    我们暴力一定会用到前缀和,那我们就要来考虑能不能用前缀和保持单调性做...

    #include<bits/stdc++.h>
    #define ll long long
    #define max(a,b) (((a)>(b))?(a):(b))
    #define min(a,b) (((a)<(b))?(a):(b))
    using namespace std;
    const ll N=101000;
    ll ans=-1e18,sum[N],n,p,l,head,tail;
    struct gg
    {
        ll id,s;
    }q[N];
    inline ll read()
    {
        ll x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    } 
    int main()
    {
        freopen("1.in","r",stdin);
        cin>>n>>p>>l;
        for(register int i=1;i<=n;++i) sum[i]=sum[i-1]+read();
        for(register int i=p+1;i<=n;i++) 
        {
            while(head<=tail&&sum[i-p]<=q[tail].s) --tail;
            q[++tail].id=i-p;q[tail].s=sum[i-p];
            while(head<=tail&&q[head].id<i-l) ++head;
            ans=max(ans,sum[i]-q[head].s);  
        }
        cout<<ans<<endl;
        return 0;
    }

    这个题我们要记住的是范围,也就是说,你每次i向前推进时,你应该把哪些点放到队列里,这里就是把i-p放进去,因为有最小长度的限制,所以

    每次枚举i时,我们队列里控制的点范围其实在(i-q,i-p)之间,这样才能保证子序列时合法的子序列...

  • 相关阅读:
    SpringMVC 注解大全
    Maven实战--- dependencies与dependencyManagement的区别
    SpringMVC5.2.0 使用到 WebDataBinderFactory.createDataBinder 方法的类
    Spring DataBinder
    mysql 查询主键外键
    objectMapper.canSerialize SpringMVC实体转JSON字符串
    整合SSM时启动Tomcat报nested exception is java.lang.NoClassDefFoundError: com/fasterxml/jackson/databind/exc/InvalidDefinitionException
    synchronizeOnSession
    init-method afterPropertiesSet BeanPostProcessor 执行顺序
    SpringMVC中重定向参数的使用以及原理解析 RedirectAttributes
  • 原文地址:https://www.cnblogs.com/gcfer/p/10598916.html
Copyright © 2011-2022 走看看