题意:
给出两个n×mn\times mn×m的矩阵A,BA,BA,B,矩阵的元素都两两互异,且属于区间[1,nm][1,nm][1,nm],求出他们最大的公共子矩阵的元素个数有多少个
Solution:
最大子矩阵问题我们考虑悬线法,重点在于如何转换至一个矩阵上解决问题。有一个技巧,我们记录AAA矩阵中元素xxx的位置为pos[x]pos[x]pos[x],以行优先或列优先都可以,这里以行优先为例,有pos[a[i][j]]=(i−1)×n+jpos[a[i][j]]=(i-1)\times n+jpos[a[i][j]]=(i−1)×n+j,这样做有什么好处?
如果我们将BBB矩阵的元素xxx替换成pos[x]pos[x]pos[x],那么在BBB内出现的AAA已有的矩阵必然是满足左右差111,上下差mmm的矩阵,这个问题悬线法就可以轻松解决了
#ifndef stdjudge
#include<bits/stdc++.h>
#endif
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<numeric>
#include<ctime>
#include<cmath>
#include<vector>
#include<bitset>
using namespace std;
using ll=long long;
const int N=1e3+5,inf=0x3fffffff;
const long long INF=0x3fffffffffffffff,mod=998244353;
int a[N][N],b[N][N],pos[N*N];
int n,m,l[N][N],r[N][N],up[N][N];
int main()
{
#ifdef stdjudge
freopen("in.txt","r",stdin);
#endif
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,tt=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&b[i][j]);
pos[b[i][j]]=++tt;
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
a[i][j]=pos[a[i][j]];
l[i][j]=r[i][j]=j;
up[i][j]=1;
}
}
for(int i=1;i<=n;i++)
{
for(int j=2;j<=m;j++)
if(a[i][j]==a[i][j-1]+1) l[i][j]=l[i][j-1];
for(int j=m-1;j>=1;j--)
if(a[i][j]==a[i][j+1]-1) r[i][j]=r[i][j+1];
}
for(int i=2;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i-1][j]+m==a[i][j])
{
l[i][j]=max(l[i][j],l[i-1][j]);
r[i][j]=min(r[i][j],r[i-1][j]);
up[i][j]=up[i-1][j]+1;
}
}
}
ll ans=-INF;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) ans=max(ans,1ll*(r[i][j]-l[i][j]+1)*up[i][j]);
cout<<ans;
return 0;
}
本文介绍了一种寻找两个矩阵间最大公共子矩阵元素数量的方法,通过将矩阵元素映射到位置,利用悬线法高效解决该问题。
720

被折叠的 条评论
为什么被折叠?



