zoukankan      html  css  js  c++  java
  • 数组的宽度 单调栈

    N个整数组成的数组,定义子数组a[i]..a[j]的宽度为:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子数组的宽度和。

    分析:

    我们只要统计每个数做为最小的数和最大的数所在区间有多少个。这样求当前数作为最大的数左右范围,这个用单调栈维护下,同理最小的也是
    然后左区间大小乘右区间大小就是这个数作为最大的出现的区间数;

    以1 5 4 2 3为例,逐个入栈计算每个数的右边界:

    1入栈 => 1

    5入栈,前面所有比5小的出栈,并将右边界设为5 => 5 (确定了1的右边界是5,对应下标为1)

    4入栈,前面所有比4小的出栈,并将右边界设为4 => 5 4

    2入栈,前面所有比2小的出栈,并将右边界设为2 => 5 4 2

    3入栈,前面所有比3小的出栈,并将右边界设为3 => 5 4 3(确定了2的右边界是3,对应下标为4)

    最后所有数出栈,将5 4 3这3个数的右边界的下标设为5。

    这样可以确认,每个数字最多进一次栈出一次栈,所有复杂度是O(n)的。

    代码:
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using namespace std;
    const int M=50007,inf=0x3f3f3f3f;
    int read(){
        int ans=0,f=1,c=getchar();
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=getchar();}
        return ans*f;
    }
    int n,w1[M],w2[M];
    int sk1[M],tp1,sk2[M],tp2;
    LL mx,mn;
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++) w1[i]=w2[i]=read();
        n++; w1[n]=inf; w2[n]=-1;
        for(int i=1;i<=n;i++){
        while(tp1&&w1[i]>=w1[sk1[tp1]]) mx+=1LL*w1[sk1[tp1]]*(i-sk1[tp1])*(sk1[tp1]-sk1[tp1-1]),tp1--;
            while(tp2&&w2[i]<=w2[sk2[tp2]]) mn+=1LL*w2[sk2[tp2]]*(i-sk2[tp2])*(sk2[tp2]-sk2[tp2-1]),tp2--;
            sk1[++tp1]=sk2[++tp2]=i;
        }
        printf("%lld
    ",mx-mn);
        return 0;
    }
     
     
  • 相关阅读:
    基于密度的optics聚类算法
    unicode编码和utf-8编码详解
    聚类分析之k-prototype算法解析
    python学习笔记之正则表达式1
    聚类分析之模糊C均值算法核心思想
    Matlab编程笔记之GUI程序转exe
    Matlab学习笔记之安装教程
    SVPWM原理分析-基于STM32 MC SDK 5.0
    Allego Quick Reports
    SVPWM-实战
  • 原文地址:https://www.cnblogs.com/Cindy-Chan/p/11203327.html
Copyright © 2011-2022 走看看