1. 程式人生 > >洛谷P1736 創意吃魚法

洛谷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)