luogu 1169 棋盘制作(单调栈/悬线)

luogu 1169 棋盘制作(单调栈/悬线)

国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。而我们的主人公小Q,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则。小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。于是小Q找到了即将参加全国信息学竞赛的你,你能帮助他么?N, M ≤ 2000。

首先,一个是棋盘的矩阵,满足相邻两个元素颜色不同。假设左上角的(1,1)是白色的格子。那么易证,横纵坐标之和是偶数的格子是白色的,是奇数的各自是黑色的。所以逆向思维,只要把给定的矩阵,横纵坐标之和同模2的一种格子反色,问题就变成了求最大的同色矩阵和同色正方形。这是最大子矩阵问题。用单调栈可以做,不过比悬线法烦一些。下面我来介绍一下悬线法。

悬线就是一端贴着不可算入矩形的区域(墙壁)的线。首先,一个最大子矩阵中一定有悬线,不然这个矩阵是可以再扩张的。所以,我们只要枚举所有悬线即可。首先n^2预处理出每个点向上向下能扩展的最大距离。然后从左向右,从右向左分别枚举一遍所有悬线(横向的),找出最大值即可。详见代码。

还有,个人感觉这种题目的思路很重要,就是把求最优解,转化为求出每个元素作为基础的最优值,然后取最优值中的最优值作为答案。

#include <cstdio>
using namespace std;

const int maxn=2005, INF=1e9;typedef int inta2[maxn][maxn];

int n, m, ans1, ans2, begin, minup, mindown;
inta2 a, up, down;

int max(int x, int y){ return x<y?y:x; }
int min(int x, int y){ return x<y?x:y; }
int sqr(int x){ return x*x; }

int main(){
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n; ++i) //转换棋盘
        for (int j=1; j<=m; ++j){
            scanf("%d", &a[i][j]);
            if (i&1) a[i][j]^=1;
            if (!(j&1)) a[i][j]^=1;
        }
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=m; ++j)
            up[i][j]=(a[i][j]==a[i-1][j]?
                up[i-1][j]+1:1);
    for (int i=n; i>0; --i)
        for (int j=1; j<=m; ++j)
            down[i][j]=(a[i][j]==a[i+1][j]?
                down[i+1][j]+1:1);
    //悬线法
    for (int color=0; color<=1; ++color)
    for (int i=1; i<=n; ++i){
        minup=mindown=INF; begin=1;
        for (int j=1; j<=m; ++j){
            if (a[i][j]!=color){
                minup=mindown=INF;
                begin=j+1; continue;
            }
            minup=min(minup, up[i][j]);
            mindown=min(mindown, down[i][j]);
            ans1=max(ans1, (minup+mindown-1)*(j-begin+1));
            ans2=max(ans2, sqr(min(minup+mindown-1, j-begin+1)));
        }
        minup=mindown=INF; begin=m;
        for (int j=m; j>0; --j){
            if (a[i][j]!=color){
                minup=mindown=INF;
                begin=j-1; continue;
            }
            minup=min(minup, up[i][j]);
            mindown=min(mindown, down[i][j]);
            ans1=max(ans1, (minup+mindown-1)*(begin-j+1));
            ans2=max(ans2, sqr(min(minup+mindown-1, begin-j+1)));
        }
    }
    printf("%d\n%d", ans2, ans1);
    return 0;
}

原文地址:https://www.cnblogs.com/MyNameIsPc/p/8445729.html

时间: 2024-07-31 04:28:59

luogu 1169 棋盘制作(单调栈/悬线)的相关文章

【ZJOI2007】棋盘制作[动规 悬线法]

[ZJOI2007]棋盘制作 悬线法 H[i,j]为点(i,j)对应的悬线的长度 L[i,j]为点(i,j)对应的悬线向左最多能够移动到的位置. R[i,j]为点(i,j)对应的悬线向右最多能够移动到的位置. 预处理:对于第i行 若(i,j)和(i,j-1)不同色则L[i,j]=L[i,j-1] R[i,j-1]=R[i,j] 若点(i,j)和点(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]) #includ

BZOJ1057[ZJOI2007]棋盘制作 [单调栈]

题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳. 而我们的主人公小Q,正是国际象棋的狂热爱好者.作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则. 小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一.小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大.

【bzoj1057】【ZJOI2007】【棋盘制作】【悬线法+dp】

Description 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳.而我们的主人公小Q,正是国际象棋的狂热爱好者.作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则.小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一.小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可

BZOJ 1057 ZJOI2007 棋盘制作 单调栈

题目大意:给定一个黑白两色的矩阵,求最大的黑白相间的子正方形和子矩阵 将奇数位置的点反色,然后就是求纯色的最大子正方形和子矩阵 将矩阵一层层剖分,每层上方是一段类似于▆▃▇▂▉的东西,用单调栈跑出每个点向左向右能拓展到的最大距离,更新答案即可 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 2020 using namespace

洛谷 P1169 [ZJOI2007]棋盘制作

2016-05-31 14:56:17 题目链接: 洛谷 P1169 [ZJOI2007]棋盘制作 题目大意: 给定一块矩形,求出满足棋盘式黑白间隔的最大矩形大小和最大正方形大小 解法: 神犇王知昆的悬线法 论文:浅谈用极大化思想解决最大子矩形问题 H[i][j]表示(i,j)向上最长连续多少距离不出现障碍点(悬线) L[i][j]表示H[i][j]这根悬线最多可以向左移到什么位置 R[i][j]表示H[i][j]这根悬线最多可以向右移到什么位置 递推方式看代码吧,很好理解的 1 //棋盘制作

【Luogu】P1169棋盘制作(单调栈)

题目链接 唉……这种题放在NOIP以前我是会做的……但是为什么现在反而不会了…… 单调栈.预处理每个点向上能扩展的最大距离,左右用两遍单调栈扫一遍.注意边界. #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<cctype> using namespace std; inline long long read(){ long long

BZOJ 1057: [ZJOI2007]棋盘制作 悬线法求最大子矩阵+dp

1057: [ZJOI2007]棋盘制作 Description 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳.而我们的主人公小Q,正是国际象棋的狂热爱好者.作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W决定将棋盘扩大以适应他们的新规则.小Q找到了一张由N*M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一.小Q想在这种纸中裁减

【BZOJ-3039&amp;1057】玉蟾宫&amp;棋盘制作 悬线法

3039: 玉蟾宫 Time Limit: 2 Sec  Memory Limit: 128 MBSubmit: 753  Solved: 444[Submit][Status][Discuss] Description 有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地.这片土地被分成N*M个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda.现在freda要在这里卖

BZOJ 1057: [ZJOI2007]棋盘制作( dp + 悬线法 )

对于第一问, 简单的dp. f(i, j)表示以(i, j)为左上角的最大正方形, f(i, j) = min( f(i + 1, j), f(i, j + 1), f(i + 1, j + 1)) + 1 (假如(i, j)和右边和下边不冲突) 第二问就是经典的悬线法解决最大子矩阵了, 维护悬线H[i][j], 左边右边延伸的最长距离.先一行一行求出这一行的L, R, 然后再从上往下扫, 维护H, L, R 写完我才发现我脑残了...最大的正方形一定是在最大子矩阵里面啊...所以其实不用dp.