洛谷P1736 创意吃鱼法

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)

猜你喜欢

转载自blog.csdn.net/Wen_Yongqi/article/details/85145614