https://www.luogu.org/problemnew/show/P1736
开始自己想:设f(i,j):以(i,j)为左上角的包含(i,j)的最大子正方形大小,则f(i,j)取决于:设t=f(i+1,j+1),(i,j)右以及下方的t个元素最多连续几个0,可以用二分+前缀和。我只会lower/upper_bound,不会手写二分
求副对角线的话,把矩阵旋转90°,再求主对角线就行了。或者再写一个差不多的DP也行。
总复杂度o(n^2logn),不加读入优化会TLE一个点,加了压线过。
#include<bits/stdc++.h>
using namespace std;
int n,m,maxn;
int a[2505][2505],b[2505][2505],d[2505][2505];
int row[2505][2505],col[2505][2505];
int Read() {
int ans=0,f=1;
char ch=getchar();
while(!isdigit(ch)) {
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)) {
ans=ans*10+ch-'0';
ch=getchar();
}
return f*ans;
}
void solve()
{
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)
{
row[i][j]=row[i][j-1]+a[i][j];
col[j][i]=col[j][i-1]+a[i][j];
}
for(int i=n;i>=1;i--)
for(int j=m;j>=1;j--)
{
int t=d[i+1][j+1];
if(row[i][j+t]-row[i][j]==0&&col[j][i+t]-col[j][i]==0&&a[i][j])d[i][j]=t+1;
else if(a[i][j])
{
d[i][j]=min((int)(upper_bound(&row[i][j]+1,&row[i][j+t]+1,row[i][j])-&row[i][j]),(int)(upper_bound(&col[j][i]+1,&col[j][i+t]+1,col[j][i])-&col[j][i]));
}
else d[i][j]=0;
}
for(int i=n;i>=1;i--)
for(int j=m;j>=1;j--)
maxn=max(maxn,d[i][j]);
}
int main()
{
freopen("input.in","r",stdin);
n=Read();m=Read();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=Read();
solve();
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)b[j][n-i+1]=a[i][j];
swap(n,m);
memset(a,0,sizeof(a));memset(d,0,sizeof(d));memset(row,0,sizeof(row));memset(col,0,sizeof(col));
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=b[i][j];
solve();
printf("%d\n",maxn);
return 0;
}
看题解,果然和前面那道“最大正方形”很像,可以把logn消掉,先预处理(i,j)向各个方向最多能延伸出去多少个0就行了。别的都一样。复杂度o(n^2)