单调栈
对于每个位置(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;
}
1017

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



