• 【BZOJ1057】[ZJOI2007] 棋盘制作(单调栈的运用)


    点此看题面

    大致题意: 给你一个(N*M)(01)矩阵,要求你分别求出最大的(01)相间的正方形和矩形(矩形也可以是正方形),并输出其面积。

    题解

    这题第一眼看去没什么思路,仔细想想,能发现这道题其实是一道单调栈的运用题。

    我们可以先对矩阵上的每一个元素进行预处理,求出以其为底的最长的 (01)

    然后对矩形(正方形)的下界进行枚举,即枚举每一行作为矩形(正方形)的下边。

    此时,我们发现,只要使连续的01柱连续距离和这些(01)柱中最短的(01)柱的高度的乘积最大,就可以求出最大的矩形(最大的正方形同理)。

    那么,我们该如何求出每一种情况呢?这时候就要用到单调栈

    我们可以建立一个严格递增的单调栈,每当单调栈栈顶的元素被弹出,我们就求出以它为右边界的最大矩阵。可以保证这样不会遗漏正确答案。

    代码

    #include<bits/stdc++.h>
    #define N 2000
    using namespace std;
    int n,m,ans1,ans2,Stack[N+5],Val[N+5],a[N+5][N+5],h[N+5][N+5];
    inline char tc()
    {
    	static char ff[100000],*A=ff,*B=ff;
    	return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0;int f=1;char ch;
    	while(!isdigit(ch=tc())) if(ch=='-') f=-1;
    	while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    	x*=f;
    }
    inline void write(int x)
    {
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10+'0');
    }
    int main()
    {
    	register int i,j;
    	for(read(n),read(m),i=1;i<=n;++i)
    		for(j=1;j<=m;++j)
    			read(a[i][j]);
    	for(i=1;i<=m;++i) h[1][i]=1;
    	for(i=2;i<=n;++i)//预处理出以每个元素为底部的最长01柱 
    		for(j=1;j<=m;++j)
    			h[i][j]=a[i-1][j]^a[i][j]?h[i-1][j]+1:1;//若其与上方的元素不同,则其可以与其上方元素构成一个01柱,否则以当前元素作为一个新的01柱
    	for(i=1;i<=n;++i)//枚举矩形的下界
    	{
    		int top,num;//top记录栈顶,num记录当前元素最大能达到的距离
    		a[i][m+1]=a[i][m]^1,h[i][m+1]=0,Stack[top=1]=1,Val[1]=h[i][1];
    		for(j=2;j<=m+1;++j) 
    		{
    			num=j;
    			if(!(a[i][j]^a[i][j-1]))//比较当前元素与前面的元素的异同,若相同,则清空栈并更新ans
    			{
    				while(top)
    				{
    					ans1=max(ans1,min(Val[top],j-Stack[top]));//先记录正方形的边长,最后再将其平方
    					ans2=max(ans2,Val[top]*(j-Stack[top]));
    					--top;
    				}
    			}
    			while(top&&h[i][j]<=Val[top])//由于要严格满足单调递增,所以要将栈中大于等于当前元素的元素弹出
    			{
    				ans1=max(ans1,min(Val[top],j-Stack[top]));
    				ans2=max(ans2,Val[top]*(j-Stack[top]));
    				num=Stack[top--];
    			}
    			Stack[++top]=num,Val[top]=h[i][j];//将当前元素加入栈
    		}
    	}
    	return write(ans1*ans1),putchar('
    '),write(ans2),0;
    }
    
  • 相关阅读:
    虚方法(virtual)和抽象方法(abstract)的区别
    IT社区
    C#中动态加载和卸载DLL
    应用程序体系结构
    Enterprise Architect 7.0入门教程
    jQuery插件开发基础1
    asp.net页面事件执行顺序
    codesmith4.1破解版
    在Web.config配置文件中自定义配置节点
    小巧实用的节拍器软件FineMetronome介绍 原创
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1057.html
Copyright © 2020-2023  润新知