• P1169 [ZJOI2007]棋盘制作 悬线法or单调栈


    思路:悬线法(or)单调栈

    提交:2次

    错因:正方形面积取错了(QwQ)

    题解:

    悬线法

    讲解:王知昆(dalao)(PPT)
    详见代码:

    #include<cstdio>
    #include<iostream>
    #define ull unsigned long long
    #define ll long long
    #define R register int
    using namespace std;
    #define pause (for(R i=1;i<=10000000000;++i))
    #define In freopen("NOIPAK++.in","r",stdin)
    #define Out freopen("out.out","w",stdout)
    namespace Fread {
    static char B[1<<15],*S=B,*D=B;
    #ifndef JACK
    #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++)
    #endif
    inline int g() {
      R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
      if(ch==EOF) return EOF; do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
    } inline bool isempty(const char& ch) {return (ch<=36||ch>=127);}
    inline void gs(char* s) {
      register char ch; while(isempty(ch=getchar()));
      do *s++=ch; while(!isempty(ch=getchar()));
    }
    } using Fread::g; using Fread::gs;
    namespace Luitaryi {
    const int N=4010;
    int n,m,a[N][N],l[N][N],r[N][N],h[N][N],S1,S2;
    inline void main() {
      n=g(),m=g();
      for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) a[i][j]=g(),l[i][j]=r[i][j]=j,h[i][j]=1;//刚开始令悬线长度为1,左右边界都是本身。 
      for(R i=1;i<=n;++i) for(R j=2;j<=m;++j) if(a[i][j]!=a[i][j-1]) l[i][j]=l[i][j-1];//在悬线长度为1时,尝试扩大左右边界 
      for(R i=1;i<=n;++i) for(R j=m-1; j;--j) if(a[i][j]!=a[i][j+1]) r[i][j]=r[i][j+1];
      for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) {
        if(i>1) if(a[i][j]!=a[i-1][j]) {//若颜色不相等,尝试合并悬线。 
          l[i][j]=max(l[i][j],l[i-1][j]),//左端点往大取 
          r[i][j]=min(r[i][j],r[i-1][j]),//右端点往小取 
          h[i][j]=h[i-1][j]+1;//悬线长度+1 
        } R a=r[i][j]-l[i][j]+1,b=min(a,h[i][j]);
        S1=max(S1,b*b),S2=max(S2,a*h[i][j]);//计算面积 
      } printf("%d
    %d
    ",S1,S2);
    }
    }
    signed main() {
      Luitaryi::main(); return 0;
    }
    

    单调栈

    其实单调栈我没有写,但是教练给的标签是单调栈。。。然后稍微想了想又看了看题解(QwQ)
    以下引用自@luogu.org lzoi_lhy

    从第一行到第n行扫一遍,维护h数组表示从当前格子往上能延伸到的黑白相间的线段(有一条边长为1的矩形)的最长长度
    我们可将当前行分为若干条线段,满足每条线段是最长的黑白相间的线段(不能再向左右延伸)
    对于每条线段,结合h数组,我们不难发现我们得到了一排高矮不一的长条状的矩形
    是不是很熟悉?用单调栈扫一遍即可
    如果遇到颜色与上一个相同的格子,就把整个栈弹出来
    注意正方形可以在数矩形的时候顺便数出来

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define X (h[stack[top]])//矩形的宽 
    #define Y (cur-stack[top-1]-1)//矩形的长 
    #define Z (min(X,Y))//正方形的边长 
    using namespace std;
    int n,m,top,cur,ans1,ans2,stack[2010],map[2010][2010],h[2010];
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;++i)
            for (int j=1;j<=m;++j) scanf("%d",&map[i][j]);
        for (int j=1;j<=n;++j){
            for (int i=1;i<=m;++i)
                if (j>1&&map[j][i]!=map[j-1][i]) ++h[i];
                else h[i]=1;
            cur=1;
            while (cur<=m){
                stack[0]=cur-1;stack[top=1]=cur++;
                while (cur<=m&&(map[j][cur]!=map[j][cur-1])){
                    while (top&&h[stack[top]]>h[cur])
                        ans1=max(ans1,Z*Z),ans2=max(ans2,X*Y),--top;
                    stack[++top]=cur++;
                }
                while (top) ans1=max(ans1,Z*Z),ans2=max(ans2,X*Y),--top;
            }
        }
        printf("%d
    %d
    ",ans1,ans2);
        return 0;
    }
    

    2019.07.22

  • 相关阅读:
    Circular dependency issuse on cocoapods version(0.36.0) 全然解决方式(非降版本号)
    Android Studio经常使用配置及使用技巧(二)
    poj 2195 Going Home(最小费最大流)
    OpenFace库(Tadas Baltrusaitis)中基于Haar Cascade Classifiers进行人脸检測的測试代码
    Divisibility by Eight
    hdu 5055(坑)
    微服务(Microservices)
    mysql 运行计划explain具体解释
    URAL 题目1297. Palindrome(后缀数组+RMQ求最长回文子串)
    Windows下将nginx安装为服务运行
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11232775.html
Copyright © 2020-2023  润新知