zoukankan      html  css  js  c++  java
  • 单调栈&&单调队列

     

    单调栈:



    Largest Rectangle in a Histogram

     POJ - 2559 

    题意:给一个柱形图,问最大矩形面积是多少。

    方法一:

    用结构体存矩形的宽和高。

    从左到右扫,如果新来的矩形高小于等于栈顶的矩形,就弹出,并计算更新面积,把栈顶的矩形宽度累加到栈里的下一个矩形。

     1 #include <iostream>
     2 #include <cstdio>
     3 using namespace std;
     4 #define ll long long
     5 const int maxn=100010;
     6 ll top;
     7 ll ans;
     8 struct Node{
     9     ll h,w;
    10 }node;
    11 Node s[maxn];
    12 int main(){
    13     ll n;
    14     while(scanf("%lld",&n)&&n){
    15             ans=0;
    16             top=0;
    17         for(int i=0;i<n;i++){
    18             ll x;
    19             scanf("%lld",&x);
    20             node.h=x;
    21             node.w=1;
    22             ll w=0;
    23             while(top&&s[top].h>=x){
    24                 Node a=s[top--];
    25                 ll temp=a.h*(a.w+w);
    26                 w+=a.w;
    27                 if(temp>ans) ans=temp;
    28             }
    29             node.w+=w;
    30             s[++top]=node;
    31         }
    32         ll w=0;
    33         while(top){
    34             Node a=s[top--];
    35             ll temp=a.h*1LL*(a.w+w);
    36             w+=a.w;
    37             if(ans<temp) ans=temp;
    38         }
    39         printf("%lld
    ",ans);
    40     }
    41 }
    View Code

    方法二: 

    扫一遍得到每个矩形左右两边第一个比它低的矩形!!

    然后直接计算更新结果。

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 #define ll long long
     7 const int maxn=100010;
     8 int s[maxn],h[maxn],L[maxn],R[maxn];
     9 int top;
    10 
    11 int main(){
    12     int n;
    13     while(scanf("%d",&n)&&n){
    14         top=0;
    15         s[top++]=0;
    16         h[n+1]=0;
    17         for(int i=1;i<=n;i++)  scanf("%d",&h[i]);
    18         for(int i=1;i<=n+1;i++){
    19             while(h[s[top-1]]>h[i]){
    20                 R[s[top-1]]=i;
    21                 top--;
    22             }
    23             L[i]=s[top-1];
    24             s[top++]=i;
    25         }
    26         ll ans=0;
    27         for(int i=1;i<=n;i++)
    28             ans=max(ans,1LL*(R[i]-L[i]-1)*h[i]);
    29         printf("%lld
    ",ans);
    30     }
    31     return 0;
    32 }
    View Code

    City Game

     POJ - 1964

    这个和上一题差不多,多了一维,可以用上一题的思路想。

    从上到下一行一行的来计算,每到达一行,计算当前各列的高度,然后维护单调栈来计算当前每一列的左右第一个比它低的列。再计算面积更新。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 const int maxn=1010;
     6 int p[maxn][maxn];
     7 int L[maxn],R[maxn],H[maxn];
     8 int s[maxn],top;
     9 
    10 int main(){
    11     int t;
    12     scanf("%d",&t);
    13     while(t--){
    14         int n,m;
    15         memset(H,0,sizeof(H));  //又是因为忘记初始化WA了。。。
    16         scanf("%d%d",&n,&m);
    17         for(int i=1;i<=n;i++)
    18         for(int j=1;j<=m;j++){
    19             char c=getchar();
    20             while(c!='F'&&c!='R') c=getchar();
    21             p[i][j]=c=='F'?1:0;
    22         }
    23         int ans=0;
    24         for(int i=1;i<=n;i++){
    25             for(int j=1;j<=m;j++){
    26                 if(p[i][j]) H[j]++;
    27                 else H[j]=0;
    28             }
    29             top=0;
    30             s[top++]=0;
    31             H[0]=-1;H[m+1]=-1;
    32             for(int j=1;j<=m+1;j++){
    33                 while(top&&H[s[top-1]]>H[j]){
    34                     R[s[top-1]]=j;
    35                     top--;
    36                 }
    37                 L[j]=s[top-1];
    38                 s[top++]=j;
    39             }
    40             for(int j=1;j<=m;j++){
    41                 ans=max(ans,H[j]*(R[j]-L[j]-1));
    42             }
    43         }
    44         printf("%d
    ",ans*3);
    45     }
    46     return 0;
    47 }
    View Code

    Bad Hair Day

     POJ - 3250 

    题意:从左往右,当前的牛可以看到第一头比它高的牛之前的所有牛,记为c[i],c[i]求和。

    考虑当前牛能被多少牛看见,维护一个单调递减栈,那么每到一头牛,栈里的牛都可以看到它。

     1 #include<cstdio>
     2 const int N=80000;
     3 int n,x,s[N],top;
     4 long long ans;
     5 int main()
     6 {
     7     scanf("%d",&n);
     8     for(int i=1;i<=n;i++)
     9     {
    10         scanf("%d",&x);
    11         while(top&&s[top]<=x)top--;
    12         ans+=top;//栈底从1开始,这样top就是元素,很方便
    13         s[++top]=x;
    14     }
    15     printf("%lld",ans);
    16     return 0;
    17 }
    View Code

    Feel Good

     POJ - 2796

    题意:给一个数组,定义s为某连续区间的长度乘以当前区间的最小值,求s的最大值。

    其实和第一题基本一样。

    先从两边各扫一遍找到每一个元素的左边界和右边界,使得它在这个区间内最小。

    然后扫一遍更新最大值即可。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 const int maxn=100010;
     6 int a[maxn],L[maxn],R[maxn];
     7 long long s[maxn];
     8 
     9 int main(){
    10     int n;
    11     scanf("%d",&n);
    12     for(int i=1;i<=n;i++){
    13         scanf("%d",&a[i]);
    14         L[i]=R[i]=i;
    15         s[i]=s[i-1]+a[i];
    16     }
    17     a[0]=a[n+1]=-1;
    18     for(int i=1;i<=n;i++){
    19         while(a[i]<=a[L[i]-1]) L[i]=L[L[i]-1];
    20     }
    21     for(int i=n;i>0;i--){
    22         while(a[i]<=a[R[i]+1]) R[i]=R[R[i]+1];
    23     }
    24     long long ans=-1;
    25     int l,r;
    26     for(int i=1;i<=n;i++){
    27         long long temp=(s[R[i]]-s[L[i]-1])*1ll*a[i];
    28         if(ans<temp){
    29             ans=temp;
    30             l=L[i];
    31             r=R[i];
    32         }
    33     }
    34     printf("%lld
    %d %d
    ",ans,l,r);
    35 }
    View Code
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #define ll long long
     5 using namespace std;
     6 const int maxn=100010;
     7 int s[maxn],top;
     8 int a[maxn],L[maxn],R[maxn];
     9 ll sum[maxn];
    10 int n;
    11 int main(){
    12     while(scanf("%d",&n)!=EOF){
    13         for(int i=1;i<=n;i++) {
    14             scanf("%d",&a[i]);
    15             sum[i]=sum[i-1]+a[i];
    16         }
    17         a[n+1]=-1;
    18         top=0;
    19         s[top++]=0;
    20         for(int i=1;i<=n+1;i++){
    21             while(top&&a[s[top-1]]>a[i]){
    22                 R[s[top-1]]=i;
    23                 top--;
    24             }
    25             L[i]=s[top-1];
    26             s[top++]=i;
    27         }
    28       //  for(int i=1;i<=n;i++){
    29          //   printf("%d %d
    ",L[i],R[i]);
    30       //  }
    31         ll ans=-1;
    32         int l,r;
    33         for(int i=1;i<=n;i++){
    34             ll temp=(sum[R[i]-1]-sum[L[i]])*a[i];
    35             if(ans<temp){
    36                 l=L[i]+1;
    37                 r=R[i]-1;
    38                 ans=temp;
    39             }
    40         }
    41         printf("%lld
    %d %d
    ",ans,l,r);
    42     }
    43 }
    View Code

    Terrible Sets

     POJ - 2082 

    题意:还是求最大矩形面积。。。

    我怎么做的单调栈都是这个题。。。

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 const int maxn=50010;
     6 
     7 int s[maxn],top;
     8 int sumw[maxn];
     9 int w[maxn],h[maxn];
    10 
    11 int main(){
    12     int n;
    13     while(scanf("%d",&n)&&n!=-1){
    14         for(int i=1;i<=n;i++){
    15             scanf("%d%d",&w[i],&h[i]);
    16             sumw[i]=sumw[i-1]+w[i];
    17         }
    18         top=0;
    19         h[n+1]=-1;
    20         s[top++]=0;
    21         int ans=-1;
    22         for(int i=1;i<=n+1;i++){
    23             while(top&&h[i]<h[s[top-1]]){
    24                 int temp=(sumw[i-1]-sumw[s[top-2]])*h[s[top-1]];
    25                 ans=max(ans,temp);
    26                 top--;
    27             }
    28             s[top++]=i;
    29         }
    30         printf("%d
    ",ans);
    31     }
    32 }
    View Code

    单调队列:



    Sliding Window

     POJ - 2823 

    题意:求长度为k的窗口里的最大值和最小值。

    以最大值为例:

    从左往右扫,

    如果当前窗口前面的元素超出窗口,弹出

    如果新扫到的元素大于区间末尾的元素,则弹出队尾,因为后面的元素比它更优,它不可能是答案。

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 const int maxn=1e6+10;
     7 int head,tail;
     8 int que[maxn];
     9 int a[maxn],n,k;
    10 
    11 int main(){
    12     while(scanf("%d%d",&n,&k)!=EOF){
    13         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    14         head=tail=0;
    15         for(int i=1;i<=n;i++){
    16             while(head!=tail&&que[head]<=i-k) head++;             //不在查询区间内,出队
    17             while(head!=tail&&a[que[tail-1]]>=a[i]) tail--;
    18             que[tail++]=i;
    19             if(i>=k) printf("%d%c",a[que[head]],i==n?'
    ':' ');
    20         }
    21         head=tail=0;
    22         for(int i=1;i<=n;i++){
    23             while(head!=tail&&que[head]<=i-k) head++;
    24             while(head!=tail&&a[que[tail-1]]<=a[i]) tail--;
    25             que[tail++]=i;
    26             if(i>=k) printf("%d%c",a[que[head]],i==n?'
    ':' ');
    27         }
    28     }
    29     return 0;
    30 }
    View Code
  • 相关阅读:
    openldap
    Java实现 洛谷 P1200 [USACO1.1]你的飞碟在这儿Your Ride Is He…
    Java实现 洛谷 P1200 [USACO1.1]你的飞碟在这儿Your Ride Is He…
    Java实现 洛谷 P2141 珠心算测验
    Java实现 洛谷 P2141 珠心算测验
    Java实现 洛谷 P2141 珠心算测验
    Java实现 洛谷 P2141 珠心算测验
    Java实现 洛谷 P2141 珠心算测验
    Java实现 洛谷 P1567 统计天数
    Java实现 洛谷 P1567 统计天数
  • 原文地址:https://www.cnblogs.com/yijiull/p/7297949.html
Copyright © 2011-2022 走看看