单调栈
对于每个位置(i,j)维护一个向下的最长的合法长度v[i][j]
然后对于某一行来说问题就转换为:
对于一个数列a[i],找一段连续的区间[l,r]是的(r-l+1)*min(l,r)
这就是一个经典的单调栈问题了
复杂度:O(n*m)
/**************************************************************
Problem: 1057
User: syh0313
Language: C++
Result: Accepted
Time:2948 ms
Memory:32888 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
using
namespace
std;
const
int
maxn=2010;
int
n,m,a[maxn][maxn],v[maxn][maxn],ans1,ans2,pre[maxn],nxt[maxn],sta[maxn],id[maxn],top;
void
solve(
int
o,
int
l,
int
r)
{
for
(
int
i=l;i<=r;i++) pre[i]=nxt[i]=0;
top=0;
for
(
int
i=l;i<=r;i++)
{
while
(top && sta[top]>=v[o][i]) top--;
if
(top==0) pre[i]=l;
else
pre[i]=id[top]+1;
top++; sta[top]=v[o][i]; id[top]=i;
}
top=0;
for
(
int
i=r;i>=l;i--)
{
while
(top && sta[top]>=v[o][i]) top--;
if
(top==0) nxt[i]=r;
else
nxt[i]=id[top]-1;
top++; sta[top]=v[o][i]; id[top]=i;
}
for
(
int
i=l;i<=r;i++)
{
ans1=max(ans1,min(v[o][i],nxt[i]-pre[i]+1)*min(v[o][i],nxt[i]-pre[i]+1));
ans2=max(ans2,v[o][i]*(nxt[i]-pre[i]+1));
}
}
int
main()
{
scanf
(
"%d%d"
,&n,&m);
for
(
int
i=1;i<=n;i++)
for
(
int
j=1;j<=m;j++)
scanf
(
"%d"
,&a[i][j]);
for
(
int
j=1;j<=m;j++)
for
(
int
i=1;i<=n;i++)
{
int
now=1;
int
k=i;
while
(k+1<=n && a[k+1][j]!=a[k][j]) {k++; now++;}
for
(
int
lc=i;lc<=k;lc++) v[lc][j]=now--;
i=k;
}
for
(
int
i=1;i<=n;i++)
for
(
int
j=1;j<=m;j++)
{
int
now=1;
int
k=j;
while
(k+1<=m && a[i][k+1]!=a[i][k]) {k++; now++;}
solve(i,j,k); j=k;
}
printf
(
"%d\n%d\n"
,ans1,ans2);
return
0;
}