洛谷P1169 [ZJOI2007]棋盘制作

博客围绕给定的n∗m(规模小于2000∗2000)的01矩形展开,要找出满足<01交替>的最大子正方形和子矩形面积。采用悬线法解题,介绍了相关变量的含义及维护方法,复杂度为O(n∗m),还推荐了洛谷排名第一的题解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.luogu.org/problemnew/show/P1169
题意:给定 n ∗ m n*m nm的01矩形,规模小于 2000 ∗ 2000 2000*2000 20002000,找出最大的满足 &lt; 01 交 替 &gt; &lt;01交替&gt; <01>的子正方形和子矩形的面积。
思路:悬线法。《训练指南》第一章也有一道悬线法的题,不过这道题要求维护的01交替较难一些。
l / r ( i , j ) : 高 为 u p ( i , j ) 的 悬 线 , 向 左 / 右 01 交 替 能 到 达 的 最 远 列 坐 标 l/r(i,j):高为up(i,j)的悬线,向左/右01交替能到达的最远列坐标 l/r(i,j):up(i,j)线,/01
u p ( i , j ) : ( i , j ) 向 上 01 交 替 的 最 长 长 度 up(i,j):(i,j)向上01交替的最长长度 up(i,j):(i,j)01
u p up up很好维护, l / r l/r l/r的话,有一个很好的性质, ( i , j ) (i,j) (ij)往上01交替的话,那么这根悬线往左移(过程中时终满足01交替),直到【单独考虑每一行的 l ( i , j ) l(i,j) l(i,j)的最大值那一列】,向右是同样的道理。
复杂度 O ( n ∗ m ) O(n*m) O(nm)
我的语言表达能力太差了,还是洛谷排名第一的题解易懂https://www.luogu.org/problemnew/solution/P1169

#include<bits/stdc++.h>
using namespace std;
#define maxn 2010

int n,m,a[maxn][maxn];
int up[maxn][maxn],l[maxn][maxn],r[maxn][maxn];
int ans1,ans2;

int main()
{
   // freopen("input.in","r",stdin);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            scanf("%d",&a[i][j]);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
            if(j==1||a[i][j]==a[i][j-1])l[i][j]=j;
            else l[i][j]=l[i][j-1];
        for(int j=m;j>=1;j--)
            if(j==m||a[i][j]==a[i][j+1])r[i][j]=j;
            else r[i][j]=r[i][j+1];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(i==1||a[i][j]==a[i-1][j])up[i][j]=1;
            else{
                up[i][j]=up[i-1][j]+1;
                l[i][j]=max(l[i][j],l[i-1][j]);
                r[i][j]=min(r[i][j],r[i-1][j]);
            }
            int width=r[i][j]-l[i][j]+1,high=up[i][j],len=min(high,width);
            ans1=max(ans1,len*len);
            ans2=max(ans2,width*high);
        }    
    }
    printf("%d\n%d\n",ans1,ans2);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值