zoukankan      html  css  js  c++  java
  • [ZJOI2007]棋盘制作 (单调栈)

    [ZJOI2007]棋盘制作

    题目描述

    国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8 imes 88×8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。

    而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则。

    小Q找到了一张由N imes MN×M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。

    不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。

    于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?

    输入输出格式

    输入格式:

    包含两个整数NN和MM,分别表示矩形纸片的长和宽。接下来的NN行包含一个N imes MN ×M的0101矩阵,表示这张矩形纸片的颜色(00表示白色,11表示黑色)。

    输出格式:

    包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋盘的面积(注意正方形和矩形是可以相交或者包含的)。

    输入输出样例

    输入样例#1:

    3 3
    1 0 1
    0 1 0
    1 0 0

    输出样例#1:

    4
    6

    说明

    对于(20\%)的数据,(N, M ≤ 80N,M≤80)

    对于(40\%)%的数据,(N, M ≤ 400N,M≤400)

    对于(100\%)的数据,(N, M ≤ 2000N,M≤2000)

    Solution

    在这之前,我们先认识一个数据结构-单调栈
    单调栈在计算最大子矩阵这一方面非常好用

    那么单调栈是什么呢?
    其实顾名思义,就是一个保持单调性的栈
    若保持单调递增
    那么在碰到一个元素小于栈顶时,我们会不断弹出栈顶,直到当前元素大于栈顶,一般就是在此过程中更新答案
    否则直接入栈

    单调递减同理

    那么来看这样一道题目:在一条水平线上方有若干个矩形,求包含于这些矩形的并集内部的最大矩形的面积(下图中的阴影部分就是答案),矩形个数(<=10^5)

    确定了单调栈,应该很好写了吧,因为矩形的宽w[]都为1,长s[]给定
    所以我们建立一个单调栈,用来保存若干个矩形,这些矩形的高度是单调递增的,从左到右依次扫描这些矩形
    如果当前矩形比栈顶矩形高,直接进栈
    否则不断弹出栈顶,在出栈过程中,我们累加每一个矩形的宽度之和,然后用当前矩形的高度乘以这个和,其最大值就是答案,整个出栈过程结束后,我们把高度为当前高度,宽为累加值的新矩阵入栈

    大致思路就是这样,那么这道题应该稍微好想了一点吧
    预处理出每一列的合法高度,然后枚举每一行,求最大子矩阵的面积大小,正方形是特殊的矩形,所以可以一并算出来

    具体细节:我们如果碰到一个不合法的元素,我们就要计算当前出栈元素累加的宽度,但是由于由于长条矩形可能在满足长度递增的情况下,并不与之前一个矩形01相间,所以我们需要另一种计算方法,但是由于这种方法不是很好讲,下面给出代码,请读者画图理解一下(以后有时间在更新)

    Code

    #include<bits/stdc++.h>
    #define rg register
    #define x (h[s[top]])
    #define y (pos-s[top-1]-1)
    #define z min(x,y)
    using namespace std;
    const int N=2e3+10;
    int n,m,top,ans1,ans2;
    int a[N][N],s[N],h[N];
    int main()
    {
    	ios::sync_with_stdio(0);
    	cin>>n>>m;
    	for(rg int i=1;i<=n;i++)
    		for(rg int j=1;j<=m;j++)
    		cin>>a[i][j];
    	for(rg int i=1;i<=n;i++) {
    		for(rg int j=1;j<=m;j++) {
    			if(a[i][j]!=a[i-1][j]) h[j]++;
    			else h[j]=1;
    		}
    		int pos=1;
    		while(pos<=m) {
    			s[top]=pos-1,s[++top]=pos++;
    			while(pos<=m && a[i][s[top]]!=a[i][pos]) {
    				while(top && h[pos]<h[s[top]])
    					ans1=max(ans1,z*z),ans2=max(ans2,x*y),top--;
    				s[++top]=pos++;
    			}
    			while(top) ans1=max(ans1,z*z),ans2=max(ans2,x*y),top--;
    		}
    	}
    	cout<<ans1<<endl<<ans2<<endl;
    	return 0;
    }
    

    博主蒟蒻,随意转载.但必须附上原文链接

    http://www.cnblogs.com/real-l/

  • 相关阅读:
    Java 强、弱、软、虚,你属于哪一种?
    为啥阿里巴巴规定要在 @Transactional 指定 rollbackFor?
    DataGrip 上手体验,真香!
    日志框架选型,Logback 还是 Log4j2?
    基于OpenLayers和ArcGIS Server REST的要素信息保存功能
    基于Openlayers和Arcgis Server REST实现地图(要素)点击查询功能
    使用OpenLayers加载ArcGIS Server矢量图层
    ArcGIS Server在线编辑功能
    使用OpenLayers显示百度地图
    如何分析SAP ABAP的SYSTEM_NO_ROLL运行时错误
  • 原文地址:https://www.cnblogs.com/real-l/p/9728689.html
Copyright © 2011-2022 走看看