【NOIP2016提高A组五校联考4】square

来源:互联网 发布:淘宝搜索词分析收费 编辑:程序博客网 时间:2024/05/23 20:55

Description

这里写图片描述

Solution

比赛的时候就想到了要二分,还有像RMQ一样的弄,就像有一道题叫做妮厨的愤怒(我的博客上有)一样,思想十分的简单,但是我没有打完TAT。
比赛之后推倒重写。

一个f数组

首先需要一个f数组f[i][j]表示以(i,j)为右下角的最大正方形的边长。
f[i][j]=min(f[i1][j],min(f[i1][j1],f[i][j1]))+1
这个十分的显然。

二分和二维RMQ

然后,最大最小值明显是用二分的思想来处理。
二分出一个mid表示答案,然后只需要在(x+mid-1,y+mid-1)到(xx,yy)这个范围内找一个最大值就好了。
只用最大值而已,那么明显RMQ值最合适不过的。
g[k][l][i][j]i2k1j2l1f[i][j]
然后,这里又有一个需要反思的地方了。
我在用RMQ在(x,y)到(xx,yy)范围内找最大值的时候一开始是用log2的方法的,然后这样时间就爆了。
后来才发现我的RMQ没有学好(主要是用的不多,这题又要卡常数),然后用了个快点的方法:比如一维的RMQ中在[x,y]中找一个最大值,首先求出q=log(xy+1)/log(2),然后最大值等于max(g[x][q],g[x+2q][q]),因为只用求最大值,所以两个区间覆盖并没有什么关系。
那么二维的RMQ也是类似的。
但是之后,还是过不了,只有90分。

卡常

首先是预处理的卡常:
1、k和l我一开始是开到10的,其实9就好了(我没有用换底公式)。
2、为什么k和l要打在前面呢?因为这样预处理的时候i和j的范围就变成了2i......n2j......m,范围会小一点。
3、去最大值优化(这个还是很有用的)。
4、去函数优化。
5、其实上面的都不是关键,最重要的是这个优化(开了我3个小时)。电脑搞这个log的速度是非常慢的,所以与其用高级的换底公式还不如直接暴力算出log(速度才O(9)而已,比打log函数快多了)。
这些优化打了,肯定能过。

Code

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=1007;int i,j,k,l,t,n,m,cas,r,mid,ans,p,q,yi,er1,lef,rig;int x,y,xx,yy;int a[maxn][maxn],f[maxn][maxn];int g[11][11][maxn][maxn],er[11];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 pan(int xx,int yy,int x,int y){    int i,j,t=0,k=0,ans=0,q;    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(g[t][k][x+(1<<t)-1][yy]>ans)ans=g[t][k][x+(1<<t)-1][yy];    if(g[t][k][xx][y+(1<<k)-1]>ans)ans=g[t][k][xx][y+(1<<k)-1];    return ans;}int main(){//  freopen("fan.in","r",stdin);//  freopen("fan.out","w",stdout);    freopen("square.in","r",stdin);    freopen("square.out","w",stdout);    scanf("%d%d",&n,&m);    er[0]=1;    fo(i,1,10)er[i]=er[i-1]*2;    fo(i,1,n)fo(j,1,m)a[i][j]=get();    for(i=1;i<=n;i++)for(j=1;j<=m;j++){        if(a[i][j]){            g[0][0][i][j]=g[0][0][i-1][j];            if(g[0][0][i][j-1]<g[0][0][i][j])g[0][0][i][j]=g[0][0][i][j-1];            if(g[0][0][i-1][j-1]<g[0][0][i][j])g[0][0][i][j]=g[0][0][i-1][j-1];            g[0][0][i][j]++;        }    }    for(i=0;(1<<i)<=n;i++){        for(j=0;(1<<j)<=m;j++){            if(i==0&&j==0)continue;            for(k=er[i];k<=n;k++)                for(l=er[j];l<=m;l++){                    if(j==0){                        g[i][j][k][l]=g[i-1][j][k][l];                        if(g[i-1][j][k-(1<<(i-1))][l]>g[i][j][k][l])g[i][j][k][l]=g[i-1][j][k-(1<<(i-1))][l];                    }                    else {                        g[i][j][k][l]=g[i][j-1][k][l];                        if(g[i][j-1][k][l-(1<<(j-1))]>g[i][j][k][l])g[i][j][k][l]=g[i][j-1][k][l-(1<<(j-1))];                    }                }        }    }    for(scanf("%d",&cas);cas;cas--){        x=get(),y=get(),xx=get(),yy=get();        if(pan(xx,yy,x,y)==0){            printf("0\n");            continue;        }        l=0,r=xx-x+1;        if(yy-y+1<r)r=yy-y+1;        while(l<r){            mid=(l+r+1)/2;            if(pan(xx,yy,x+mid-1,y+mid-1)>=mid)l=mid;else r=mid-1;        }        printf("%d\n",l);    }}
2 0
原创粉丝点击