NOIP提高组【JZOJ4817】square

来源:互联网 发布:辽宁大石药业淘宝 编辑:程序博客网 时间:2024/06/06 16:39

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

我们首先可以预处理出f[i][j]表示以(i,j)为右下角的最大正方形的边长。这显然可以在输入时处理出来。f[i][j]=min(f[i1][j1],f[i1][j],f[i][j1])+1。对于一个询问(x,y,xx,yy),我们其实是可以二分答案的。假设我们当前二分出来的答案为mid,那么我们就可以在(x+mid-1,y+mid-1,xx,yy)这个区间那里找一个最大正方形,若最大正方形的边长大于mid就往右走。那么现在问题是:如何在(x+mid-1,y+mid-1,xx,yy)这个区间内找一个最大的f[i][j]呢?我们想到用二维rmq来解决。设g[x][y][i][j]表示(i-2x+1,j-2y+1,i,j)这个区间内的最大的f值。然后设t=log2xx(x+mid1),k=log2yy(y+mid1),那么一个询问(x+mid-1,y+mid-1,xx,yy)的中的最大f值则是max(g[t][k][xx][yy],g[t][k][x+mid1+2t][y+mid1+2k],g[t][k][x+mid1+2t][yy],g[t][k][xx][y+mid1+2k])。(若看不懂的话可以手动画一下图,画一下就懂了。)注意一下,log的运算在c++中是很慢的,建议手打,否则你会像博主一样卡了3小时的常还是90分……

代码

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const int maxn=1005;int a[maxn][maxn],n,i,t,j,k,l,m,p,x,y,xx,yy,r,mid,l1;int f[maxn][maxn],g[11][11][maxn][maxn],ans;int pan(int x,int y){    int i,j,t=0,k=0;    while (x+(1<<(t+1))-1<=xx) t++;    while (y+(1<<(k+1))-1<=yy) k++;    ans=g[t][k][xx][yy];    if (g[t][k][x+(1<<t)-1][y+(1<<k)-1]>ans) ans=g[t][k][x+(1<<t)-1][y+(1<<k)-1];    if (ans<g[t][k][x+(1<<t)-1][yy]) ans=g[t][k][x+(1<<t)-1][yy];    if (ans<g[t][k][xx][y+(1<<k)-1]) ans=g[t][k][xx][y+(1<<k)-1];    return ans;}int get(){    char ch=getchar();int x=0;    while (ch<'0' || ch>'9') ch=getchar();    while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();    return x;}int main(){    freopen("square.in","r",stdin);freopen("square.out","w",stdout);    scanf("%d%d",&n,&m);    for (i=1;i<=n;i++)        for (j=1;j<=m;j++){            scanf("%d",&a[i][j]);            if (a[i][j]) f[i][j]=min(min(f[i-1][j-1],f[i-1][j]),f[i][j-1])+1;            g[0][0][i][j]=f[i][j];        }    l1=log(n)/log(2);    p=log(m)/log(2);    for (i=0;i<=l1;i++)        for (j=0;j<=p;j++){            if (!i && !j) continue;            for (x=(1<<i);x<=n;x++)                for (y=(1<<j);y<=m;y++){                    if (i){                        if (g[i-1][j][x][y]>g[i-1][j][x-(1<<(i-1))][y]) g[i][j][x][y]=g[i-1][j][x][y];                        else g[i][j][x][y]=g[i-1][j][x-(1<<(i-1))][y];                    }                    else{                        if (g[i][j-1][x][y]>g[i][j-1][x][y-(1<<(j-1))]) g[i][j][x][y]=g[i][j-1][x][y];                        else g[i][j][x][y]=g[i][j-1][x][y-(1<<(j-1))];                    }                }        }    scanf("%d",&m);    while (m){        scanf("%d%d%d%d",&x,&y,&xx,&yy);        //x=get();y=get();xx=get();yy=get();        l=0;r=min(yy-y+1,xx-x+1);        while (l<r){            mid=(l+r+1)/2;            if (pan(x+mid-1,y+mid-1)>=mid) l=mid;            else r=mid-1;        }        printf("%d\n",l);        m--;    }}
3 0
原创粉丝点击