CF407D Largest Submatrix 3 题解

Codeforces
Luogu

Description.

给定一个 \(n\times m\) 的矩阵,求最大的子矩阵,满足其没有重复元素。
\(n\le 400\)

Solution1.

复杂度 \(O(n^3\log n)\)无法通过

考虑枚举矩阵上边界和下边界。
对于每个点维护如果它作为右边界所能到达的最左边界。
然后,每次下边界下移,我们发现会更新一些点的信息。
就是如果新加入的一行中一个元素在过去出现过,我们就需要跟新它。
然后直接用一个 set 维护,每次查询前驱后继。

Solution2.

考虑在 Solution1 的基础上优化。
考虑更换枚举方向,上边界从下往上移动,下边界从上往下移动。
维护的东西和 Solution1 相同,下边界下移,可以利用上一次求出的信息。
上边界上移,从删数变成了加数,删数的话必须重新处理,加数就可以利用之前的性质了。
然后相当于每次多出来了最上面一行,根本不需要用 set

Coding.

点击查看 Solution1 代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
const int N=405;int n,m,a[N][N],L[N][N];set<int>st[N*N];
inline void ckmx(int &a,int b) {a>b?a:a=b;}
int main()
{
	read(n,m);for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]);
	int rs=0;for(int up=1;up<=n;up++)
	{
		for(int dw=up-1;dw<=n;dw++) for(int r=1;r<=m;r++) L[dw][r]=1;
		for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++)
		{
			int vl=a[dw][r];ckmx(L[dw][r],max(L[dw][r-1],L[dw-1][r]));
			if(!st[vl].empty()&&*st[vl].begin()<=r) ckmx(L[dw][r],*--st[vl].upper_bound(r)+1);
			if(!st[vl].empty()&&*st[vl].rbegin()>=r) ckmx(L[dw][*st[vl].lower_bound(r)],r+1);
			st[a[dw][r]].insert(r);
		}
		for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++) rs=max(rs,(r-L[dw][r]+1)*(dw-up+1));
		//for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++) printf("%d%c",(r-L[dw][r]+1)*(dw-up+1),r==m?'\n':' ');
		//for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) printf("%d%c",L[i][j],j==m?'\n':' ');
		for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++) st[a[dw][r]].clear();
	}
	return printf("%d\n",rs),0;
}
点击查看 Solution2 代码
//是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
const int N=405;int n,m,a[N][N],L[N][N],ls[N][N],tn[N*N];
inline void ckmx(int &a,int b) {a>b?a:a=b;}
int main()
{
	read(n,m);for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]);
	int rs=0;for(int up=n;up>=1;up--)
	{
		for(int l=1;l<=m;l++)
			ls[up][l]=max(ls[up][l-1],tn[a[up][l]]+1),
			tn[a[up][l]]=l,rs=max(rs,l-ls[up][l]+1);
		for(int l=1;l<=m;l++) tn[a[up][l]]=0;
		for(int dw=up+1;dw<=n;dw++)
		{
			for(int l=1;l<=m;l++)
			{
				ls[dw][l]=a[up][l]^a[dw][l]?max(ls[dw][l],max(tn[a[up][l]],tn[a[dw][l]])+1):l+1;
				ckmx(ls[dw][l],max(ls[dw-1][l],ls[dw][l-1])),tn[a[up][l]]=tn[a[dw][l]]=l;
				rs=max(rs,(dw-up+1)*(l-ls[dw][l]+1));
			}
			for(int l=1;l<=m;l++) tn[a[up][l]]=tn[a[dw][l]]=0;
		}
	}
	return printf("%d\n",rs),0;
}
原文地址:https://www.cnblogs.com/pealfrog/p/15194064.html