P1169 [ZJOI2007]棋盘制作(悬线法dp)

https://www.luogu.com.cn/problem/P1169


用途:
 解决给定矩阵中满足条件的最大子矩阵
做法:
用一条线(横竖貌似都行)左右移动直到不满足约束条件或者到达边界
定义几个东西:
    left[i][j]:代表从(i,j)能到达的最左位置
    right[i][j]:代表从(i,j)能到达的最右位置
    up[i][j]:代表从(i,j)向上扩展最长长度.
这里给出递推公式:
   left[i][j]=max(left[i][j],left[i-1][j])
   right[i][j]=min(right[i][j],right[i-1][j])

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=2010;
typedef int LL;
LL ma[maxn][maxn],qleft[maxn][maxn],qright[maxn][maxn],up[maxn][maxn];
LL n,m;
int main(void)
{
  cin.tie(0);std::ios::sync_with_stdio(false);
  cin>>n>>m;
  for(LL i=1;i<=n;i++){
    for(LL j=1;j<=m;j++){
        cin>>ma[i][j];
        qleft[i][j]=qright[i][j]=j;
        up[i][j]=1;
    }
  }
  for(LL i=1;i<=n;i++){
    for(LL j=2;j<=m;j++){
        if(ma[i][j]!=ma[i][j-1]){
            qleft[i][j]=qleft[i][j-1];
        }
    }
  }
  for(LL i=1;i<=n;i++){
    for(LL j=m-1;j>=1;j--){
        if(ma[i][j]!=ma[i][j+1]){
            qright[i][j]=qright[i][j+1];
        }
    }
  }
  LL area1=0;LL area2=0;
  for(LL i=1;i<=n;i++){
    for(LL j=1;j<=m;j++){
        if(i>1&&ma[i][j]!=ma[i-1][j]){
            qleft[i][j]=max(qleft[i][j],qleft[i-1][j]);
            qright[i][j]=min(qright[i][j],qright[i-1][j]);
            up[i][j]=up[i-1][j]+1;
        }
        LL a=qright[i][j]-qleft[i][j]+1;
        LL b=min(a,up[i][j]);
        area1=max(area1,b*b);
        area2=max(area2,a*up[i][j]);
    }
  }
  cout<<area1<<endl<<area2<<endl;
  return 0;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/114897764
今日推荐