[BZOJ 1057][ZJOI 2007]棋盘制作(最大全0/1子矩阵)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1057

这题好像很早之前就看到过。。。那时候我还只会玩脚丫子,做这题完全像SB一样,记得那时我做了一会就放弃了。

如今看到这题感觉好做多了,此题预处理很巧妙,我们看一个棋盘,它的所有黑点的行标奇偶性都相同,列标的奇偶性也都相同。白点一样。

于是我们就可以预处理下,对于所有行标和列标奇偶性相同的点,保持它们的颜色不变,奇偶性不相同的点,反转它们的颜色,于是预处理后,我们要找的矩形在整个大棋盘中的颜色一定是一样的。

然后直接套用最大全0/1子矩阵就OK了。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

#define MAXN 2200

using namespace std;

int n,m;
int map[MAXN][MAXN];
int h[MAXN],l[MAXN],r[MAXN];

int work1(int clr) //求最大全clr色的子矩阵(必须是正方形)
{
    int maxSqr=0;
    memset(h,0,sizeof(h));
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(map[i][j]==clr)
                h[j]++;
            else h[j]=0;
        }
        for(int j=1;j<=m;j++)
        {
            l[j]=j;
            while(l[j]>1&&h[l[j]-1]>=h[j])
                l[j]=l[l[j]-1];
        }
        for(int j=m;j>=1;j--)
        {
            r[j]=j;
            while(r[j]<m&&h[r[j]+1]>=h[j])
                r[j]=r[r[j]+1];
        }
        for(int j=1;j<=m;j++)
        {
            int nowsqr=min(h[j],r[j]-l[j]+1);
            nowsqr*=nowsqr;
            if(nowsqr>maxSqr)
                maxSqr=nowsqr;
        }
    }
    return maxSqr;
}

int work2(int clr) //求最大全clr色的子矩阵(不限于正方形)
{
    int maxSqr=0;
    memset(h,0,sizeof(h));
    memset(l,0,sizeof(l));
    memset(r,0,sizeof(r));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(map[i][j]==clr)
                h[j]++;
            else h[j]=0;
        }
        for(int j=1;j<=m;j++)
        {
            l[j]=j;
            while(l[j]>1&&h[l[j]-1]>=h[j])
                l[j]=l[l[j]-1];
        }
        for(int j=m;j>=1;j--)
        {
            r[j]=j;
            while(r[j]<m&&h[r[j]+1]>=h[j])
                r[j]=r[r[j]+1];
        }
        for(int j=1;j<=m;j++)
        {
            if(h[j]*(r[j]-l[j]+1)>maxSqr)
                maxSqr=h[j]*(r[j]-l[j]+1);
        }
    }
    return maxSqr;
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            int clr;
            scanf("%d",&clr);
            if(i%2==j%2)
                map[i][j]=clr;
            else
                map[i][j]=1-clr;
        }
    printf("%d\n%d\n",max(work1(1),work1(0)),max(work2(1),work2(0)));
    return 0;
}



时间: 2024-10-12 12:42:24

[BZOJ 1057][ZJOI 2007]棋盘制作(最大全0/1子矩阵)的相关文章

BZOJ 1057 ZJOI 2007 棋盘制作 DP+悬线法

题目大意:给出一个由01形成的矩阵,问这个矩阵中最大面积的正方形和矩形,其中任意一个方块相邻的都是不同的格子. 思路:其实吧所有(i + j)&1的位置上的数字异或一下,就变成都是0或者都是1的最大正方形和矩形了.第一问就是水DP,第二问可以单调栈或者悬线.都很好写. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define

【BZOJ 1057】 [ZJOI2007]棋盘制作

1057: [ZJOI2007]棋盘制作 Time Limit: 20 Sec  Memory Limit: 162 MB Submit: 1496  Solved: 753 [Submit][Status] Description 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳.而我们的主人公小Q,正是国际象棋的狂热爱好者.作为一个顶尖高手,他已不满足于普通的棋盘

BZOJ 1057 棋盘制作(最大黑白相间子矩阵)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1057 题意:给出一个只包含01的矩阵.找出一个01相间的最大的正方形子矩阵?找出一个01相间的最大的长方形子矩阵? 思路:一行一行扫描,对于某一行,记录每列 向上延伸的最大长度,记为h.然后再求出每列向右向左延伸的最大距离.比如2122345421,第4个位置的2向左延伸到3向右延伸到9.我们就是要求 出这个东西.我们用类似并查集思想.以向左为例.L[j]初始时指向j.从左向右扫描,对

BZOJ 1093 ZJOI 2007 最大半连通子图 强联通分量+拓扑图DP

题目大意:定义半连通图:图中任意两点之间可以单向到达.求一个图的最大半连通子图,和这个图最大半连通子图的个数. 思路:半连通图并不是一定要没有环..这题意让我理解的.. 其实想法什么的不难,想明白了也不难写.因为要保证半连通,所以要先处理出一个图的联通状况.先用Tarjan缩点得到DAG,在这个DAG上找到最长链的长度就是第一问的答案.第二问可以先找到所有f值等于答案的点,在这些点上反向记忆化搜索DP. 注意一个小地方,ans的初值是最大的scc的大小,如果是0的化会wa一个点. CODE: #

[BZOJ 1095] [ZJOI 2007]Hide 捉迷藏

在BZ上连续MLE n次后,终于A了. 自己YY的动态点分写法,思路还是很清楚的,但是比较卡内存. 用到了MAP导致复杂度比其他的代码多了一个log,看来需要去借鉴一下别人怎么写的. 1 /* 2 动态树分治 3 BZOJ1095 4 全局路径查询 5 单点修改,全局查询 6 */ 7 #include<cstdio> 8 #include<iostream> 9 #include<cstdlib> 10 #include<cstring> 11 #incl

BZOJ 1096 ZJOI 2007 仓库建设 斜率优化DP

题目大意:山坡上有一些仓库,下雨了,要把所有仓库中的东西转移出来,每转移一单位的东西走一个单位长度需要花费1,在i处建立一个仓库需要花费cost[i],求最小的花费. 思路:和小P的牧场好像啊... 记录两个前缀和,sum[i] = Σsrc[i] _sum[i] = Σsrc[i] * pos[i], 然后DP方程:f[i] = f[j] + (sum[i] - sum[j]) * pos[i] - _sum[i] + _sum[j] + cost[i] 注意转换long long 数据有可能

BZOJ 1058 ZJOI 2007 报表统计 平衡树

题目大意:给出一个序列,有几个操作,询问相邻两个数的差值的绝对值的最小值,排序后差值绝对值的最小值. 思路:简单用平衡树或者set水一下就行了. (我个沙茶最开始sort_min还用的set维护 CODE: #include <set> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 500010 #define I

BZOJ 1060 ZJOI 2007 时态同步 树形DP

题目大意:给出一个有根树,树上的边有边权.现在可以将一个边的边权的值+1,要想使得根节点到所有叶子节点的距离相等,最少需要多少个+1操作. 思路:当只考虑以一个节点为根的子树的时候,就必须要保证这个根节点到所有这个子树中的叶子节点的距离相等,才能保证最终根节点到所有叶子节点的距离都相等.所以就深搜一次,对于每个节点求出到这个节点的最长距离,将所有其他的边加成这个最长距离,记录答案. 但是这样并不能AC,因为标称是错的,它没有开long long ,于是乎我们也要开int才能AC..-.- COD

最大全0/1子矩阵的探究

by MedalPluS [问题模型] 给定一个n*n的矩阵,求矩阵中面积最大的一个值全是0或1的子矩阵 [分析] (这里n*n完全可以改为n*m,但由于种种原因,等下代码里是n*n) 首先很容易想到一种解法,枚举这个子矩阵的左上方,和右下方,然后暴力统计,这样时间复杂度O(N6),这种做法很广泛 这肯定是不能满足我们的需求,那么应该怎么办呢?我们发现O(n2)的时间浪费在统计上,我们可以使用前缀和的手段,预处理 这样时间复杂度O(n4),还是很垃圾 在暴力种种优化都不行的时候,想一想贪心或者数