dp/单调栈

来源:互联网 发布:淘宝女装模特名字大全 编辑:程序博客网 时间:2024/06/16 05:28

题目:hdu1506

题意:一个柱形图,宽均为1.内部最大的矩形的面积。

解答1:刚开始想的是从某个区间内找小的高遍历所有区间找出最大的矩形。但是复杂度太高啦!

    正确的解答:

从每一条出发,分别求出这一条左边连续比它高的和右边连续比它高的坐标。然后遍历一遍便可以求出最大值。

左右!!!可以分别从左边和右边遍历求!!!

以左边为例:

如果左边那个比它高,那么比它左边还高的一定比它还高!

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>using namespace std;const int MAXN = 100000 + 10;long long int a[MAXN],r[MAXN],l[MAXN];int main(){    long long int n;    while(~scanf("%lld",&n) && n)    {        for(int i = 1;i <= n;i++)            scanf("%lld",&a[i]);        memset(l,0,sizeof(l));        memset(r,0,sizeof(r));        l[1] = 1;        r[n] = n;        for(int i = 2;i <= n;i++)        {            int tmp = i;            while(tmp > 1 && a[tmp-1] >= a[i])                tmp = l[tmp-1];            l[i] = tmp;        }        for(int i = n-1;i >= 1;i--)        {            int tmp = i;            while(tmp < n && a[tmp+1] >= a[i])                tmp = r[tmp+1];            r[i] = tmp;        }        long long int ans = 0;        for(int i = 1;i <= n;i++)        {            ans = max(ans,(long long int)((r[i]-l[i]+1)*a[i]));        }        printf("%lld\n",ans);    }    return 0;}

解答2:从左、从右各维护一个单调栈。

单调栈:栈里面的元素是单调的(从小到大或者从大到小)

1、如果栈里元素从小到大:可以直接找到从该位置往左,第一个比它小的元素。

2、如果栈里元素从大到小:可以直接找到从该位置往右,第一个比它大的元素。

这个题,要找到一个位置往左、往右,第一个比它小的元素(如果比它大就可以扩展)

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>using namespace std;const int MAXN = 100005;long long int a[MAXN],l[MAXN],r[MAXN];struct g{    long long int h,n;};g q1[MAXN],q2[MAXN];int main(){    int N;    while(~scanf("%d",&N) && N)    {        for(int i = 1;i <= N;i++)            scanf("%d",&a[i]);        long long int ans = 0;        int top = 0;        q1[0].h = 0;        q1[0].n = 0;        q1[++top].h = a[1];        q1[top].n = 1;        l[1] = 1;        for(int i = 2;i <= N;i++)        {            if(a[i] > q1[top].h)            {                q1[++top].h = a[i];                q1[top].n = i;                l[i] = i;            }            else            {                while(q1[top].h >= a[i] && top >= 1)                    top--;                q1[++top].h = a[i];                q1[top].n = i;                l[i] = q1[top-1].n + 1;            }        }        top = 0;        q1[0].h = 0;        q1[0].n = N+1;        q1[++top].h = a[N];        q1[top].n = N;        r[N] = N;        for(int i = N-1;i >= 1;i--)        {            if(a[i] > q1[top].h)            {                q1[++top].h = a[i];                q1[top].n = i;                r[i] = i;            }            else            {                while(q1[top].h >= a[i] && top >= 1)                    top--;                q1[++top].n = i;                q1[top].h = a[i];                r[i] = q1[top-1].n - 1;            }        }        for(int i = 1;i <= N;i++)            ans = max(ans,(long long int)((r[i]-l[i]+1)*a[i]));        printf("%lld\n",ans);    }    return 0;}

解答3:依然是单调栈。但是只扫一遍。

有以下结论:

1、如果可以直接入栈,那么它可以向左扩展的长度为1(它自己)。

2、第二个出栈的元素的右宽是前一个出栈的元素的总宽。

3、h的左宽是上一个出栈元素的总宽。

进栈的时候你只能知道它向左扩展的长度(记录下来),出栈的时候你可以算出它向右扩展的长度(出栈意味着它比当前高度要高,就说明它向右扩展不能扩展到当前元素了,那么这个向右扩展的长度是几呢?)

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>using namespace std;int main(){    int n,h;    int q[100005],l[100005];    while(~scanf("%d",&n)&&n)    {        long long int ans = 0;        memset(q,-1,sizeof(q));        memset(l,0,sizeof(l));        int top = 0;        for(int i = 1;i <= n+1;i++)        {            if(i!=n+1)                scanf("%d",&h);            else                h = 0;//最后把所有的元素弹出栈            if(h > q[top])                q[++top] = h,l[top] = 1;//直接进,向左扩展为1(自己)            else//凡是出栈的元素的高度都比h高(向右扩展不到当前的元素)            {                long long int r = 0;                while(h <= q[top])                {                    ans = max(ans,q[top]*(l[top]+r));                    r += l[top--];                }                q[++top] = h;                l[top] = r + 1;//加上自己            }        }        printf("%lld\n",ans);    }    return 0;}


0 0
原创粉丝点击