• 菜需捆的 单调栈 刷题记录


    单调栈的一些性质(单增为例)

    • 在栈里的元素一定比后面的都要小(当前走到的)
    • 可以访问到第一个小于我的元素下标(就是在栈里第一个小于我的那个元素)
    • 如果我在栈里是第一个元素,说明我比前面的元素都小(考虑最小的那个元素)

    BZOJ1113: [Poi2008]海报PLA

    • 单调栈扫一遍就是了,给出的矩形的长没有什么用,只看矩形的宽,出栈的时候ans++,最后统计栈里元素个数,加到ans里
    • 注意的地方:当栈里最大元素跟当前相同时不进栈也不加ans
    • 代码:
      #include <bits/stdc++.h>
      #define nmax 250010
       
      using namespace std;
      typedef long long ll;
      int n,idx=0;
      ll ans=0;
      ll s[nmax]; //单调递增的栈
       
      int main(){
          cin>>n;
          ll a,b;
          scanf("%lld%lld",&a,&b);
          s[0]=b;
          for (int i=1; i<n; i++) {
              scanf("%lld%lld",&a,&b);
              //把b入栈
               while(s[idx]>b){ ans++; idx--; }
              if(s[idx]!=b) s[++idx]=b;
          }
          //统计栈内不同的元素个数
          for (int i=idx; i>0; i--){
              if(s[i]!=s[i-1]) ans++;
          }
          ans++;
          cout<<ans<<endl;
          return 0;
      }    
      ヽ(✿゚▽゚)ノ

    1012: [JSOI2008]最大数maxnumber

    • 题意:要支持两种操作,1.末尾插入一个数,2.查询当前数列中末尾L个数中的最大的数,并输出这个数的值
    • 只需要维护一个单调下降的栈就可以了,因为后面的数比我还大的话我在所有的查询里都不会再有贡献了。
    • 注意还有一个前缀和和二分查找的小技巧
    • 代码:
       1 #include <bits/stdc++.h>
       2 #define nmax 200005
       3  
       4 using namespace std;
       5 typedef long long ll;
       6 int op,is=0;
       7 ll mod,x,tmp=0,l=0;
       8 char in[10];
       9 ll s[nmax],num[nmax]={0};
      10  
      11 int main(){
      12     scanf("%ld%lld",&op,&mod);
      13     for (int i=0; i<op; i++) {
      14         scanf("%s%lld",in,&x);
      15         if( in[0]=='A' ){
      16                 l++;
      17          x=(x+tmp)%mod;
      18             int ta=0;
      19             while( s[is]<=x && is>=0 ) {
      20                 s[is]=x;
      21                 ta+=( num[is]-num[is-1] );
      22                 is--;
      23             }
      24             s[++is]=x;
      25             num[is]=ta+num[is-1]+1;
      26  
      27         }else{
      28             int p=lower_bound(num,num+is+1,l-x+1)-num;
      29             tmp=s[p];
      30             printf("%lld
      ",s[p]);
      31         }
      32     }
      33     return 0;
      34 }        
      View Code

     

    洛谷P4147 玉蟾宫

    • 最大子矩阵问题
    • 一行一行的处理,保证统计不会漏掉极大子矩阵.
    • 在单调栈里放两个值,下标和长度
    • 代码:
       1 #include <bits/stdc++.h>
       2 #define nmax 1005
       3 
       4 using namespace std;
       5 char in[10];
       6 char M[nmax][nmax];
       7 int n,m,is;
       8 int t[nmax][nmax],d[nmax][nmax];
       9 int s[nmax][2];
      10 
      11 int main(){
      12     cin>>n>>m;
      13     for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) { scanf("%s",in); M[i][j]=in[0]; }
      14     for (int i=1; i<=m; i++) {
      15         int nowr=0;
      16         for (int j=1; j<=n; j++) {
      17             if(M[j][i]=='R') nowr=j;
      18             t[j][i]=j-nowr;  //可行长度
      19         }
      20     }
      21     //开单调栈一顿扫
      22     for (int i=1; i<=n; i++) {
      23         is=0;
      24         s[is][0]=t[i][1];
      25         s[is][1]=1;
      26         for (int j=2; j<=m; j++) {
      27             while(t[i][j]<s[is][0]){  //0是值,1是下标
      28                 int l;
      29                 for (l=is-1; s[l][0]==s[is][0]&&l>=0; l--){}
      30                 l=s[l][1];
      31                 d[i][ s[is][1] ]=s[is][0]*(j-l-1);
      32                 is--;
      33             }
      34             is++;
      35             s[is][1]=j;
      36             s[is][0]=t[i][j];
      37         }
      38         for (; is>=0; is--){
      39             int l;
      40             for (l=is-1; s[l][0]==s[is][0]&&l>=0; l--){}
      41             l=s[l][1];
      42             d[i][ s[is][1] ]=s[is][0]*(m-l);
      43         }
      44     }
      45     int ans=0;
      46     for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) ans=max(ans,d[i][j]);
      47     cout<<3*ans<<endl;
      48     return 0;
      49 }
      哦呼

    BZOJ1057 [ZJOI2007]棋盘制作

    • 跟上面一题一样,注意横排不合法时推入长度为0的
    • 代码:
       1 #include <bits/stdc++.h>
       2 #define nmax 2005
       3 
       4 using namespace std;
       5 char in[10];
       6 int M[nmax][nmax];
       7 int n,m,is;
       8 int t[nmax][nmax],d[nmax][nmax],d2[nmax][nmax];
       9 int s[nmax][2];
      10 
      11 void mypop(int i,int x){  //把is弹出去
      12     if(!s[is][0]) { is--; return; }
      13     int l;
      14     for (l=is-1; s[l][0]==s[is][0]&&l>=0; l--){}
      15     if( s[l][0]!=s[is][0] ) l=s[l][1]+1;
      16     if(is==0) l=1;
      17     d[i][ s[is][1] ]=s[is][0]*(x-l+1);
      18     int t=min( x-l+1 , s[is][0] );
      19     d2[i][ s[is][1] ]=t*t;
      20     is--;
      21 }
      22 
      23 int main(){
      24     cin>>n>>m;
      25     for (int i=1; i<=n; i++) for (int j=1; j<=m; j++)  scanf("%d",&M[i][j]);
      26     for (int i=1; i<=m; i++) {
      27         int nowr=0;
      28         for (int j=1; j<=n; j++) {
      29             t[j][i]=j-nowr;  //可行长度
      30             if(M[j][i]==M[j+1][i]) nowr=j;
      31         }
      32     }
      33     for (int i=1; i<=n; i++) {
      34         is=0;
      35         s[is][0]=t[i][1];//0是值,1是下标
      36         s[is][1]=1;
      37         for (int j=2; j<=m; j++) {
      38             if( M[i][j] == M[i][j-1] ) { while(is>=0) mypop(i,j-1); s[++is][1]=j-1; s[is][0]=0; }
      39             else while(t[i][j]<s[is][0]) mypop(i,j-1);
      40             s[++is][1]=j;
      41             s[is][0]=t[i][j];
      42         }
      43         while(is>=0) mypop(i,m);
      44     }
      45     int ans1=0,ans2=0;
      46     for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) { ans1=max(ans1,d[i][j]); ans2=max(ans2,d2[i][j]); }
      47     cout<<ans2<<endl<<ans1<<endl;
      48     return 0;
      49 }
      quq
  • 相关阅读:
    利用 .NET Framework 命令行工具
    和AI机器人Alice的一段聊天记录
    WINDOWS自启动程序的10大隐身之所
    开放式开发/开源项目TimeDog[C#WindowsApp]
    Microsoft月度中文速递
    新安装的VS2003出现了一个问题不能新建项目!
    实例构造器和类型构造器的一些比较
    C++ 模板里面的typename
    vim 折叠的用法
    Redis3:持久化
  • 原文地址:https://www.cnblogs.com/jiecaoer/p/11296347.html
Copyright © 2020-2023  润新知