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

来源:互联网 发布:算法导论吧 编辑:程序博客网 时间:2024/05/29 14:28

square

题目大意

给出一个n*m的网格,有些网格上有障碍物,有些没有,现在DDX想要在这个网格上找一个正方形,要求这个正方形内没有障碍物。
现在给出T个询问,每个询问给出四个数x1,y1,x2,y2,要求找出的正方形不能有一部分在左上角为(x1,y1),右下角为(x2,y2)的矩形外,问此时满足上述条件的正方形的最大边长。

数据范围

这里写图片描述

题解

首先,用n*m的算法求出以(i,j)为右下角的满足题意正方形的最大边长。转移明显为:

Fx,y=min(Fx1,y,Fx,y1,Fx1,y1)+1;

用图片来解释就是:
这里写图片描述
由于有边界限制,所以某些以(i,j)为右下角的正方形会被限制住,所以我们考虑二分答案,假设我们二分出的值为mid,除了红色区域的部分的当成右下角时边长才可能超过mid,所以我们需要看一下在左上角为(x1+mid-1,y1+mid-1),右下角为(x2,y2)的矩阵中,Fi,j的最大值,若最大值大于等于mid,说明该答案可行,二分上调,反之不行。(正确性显然
附图理解:
这里写图片描述
求二维的最大值用二维RMQ维护。(即RMQ套RMQ)

Code(Pascal)

var    n,m,j,k,l,i,nf,mf,t,x1,x2,y1,y2,le,mi,ri,i1:longint;    cf:array[0..10] of longint;    f:array[0..10,0..10,0..1000,0..1000] of longint;//为了减少寻址时间,小的两维要前置    x,a:array[0..1020,0..1020] of longint;function max(a,b:int64):int64;    begin        if a>b then exit(a)        else exit(b);    end;function min(a,b:int64):int64;    begin        if a<b then exit(a)        else exit(b);    end;function ok(o:int64):boolean;    var        aa,bb,xx,yy,fn,fm:longint;    begin        xx:=x1+o-1;        yy:=y1+o-1;        fn:=trunc(ln(x2-xx+1)/ln(2));        fm:=trunc(ln(y2-yy+1)/ln(2));        aa:=max(f[fn,fm,xx,yy],f[fn,fm,xx,y2-cf[fm]+1]);        bb:=max(f[fn,fm,x2-cf[fn]+1,yy],f[fn,fm,x2-cf[fn]+1,y2-cf[fm]+1]);        if max(aa,bb)>=o then exit(true)        else exit(false);    end;begin    readln(n,m);    for i:=1 to n do    begin        for l:=1 to m do        read(a[i,l]);        readln;    end;    cf[0]:=1;    for i:=1 to 10 do    cf[i]:=cf[i-1]*2;    for i:=1 to n do    for l:=1 to m do    if a[i,l]<>1 then x[i,l]:=0    else x[i,l]:=min(x[i-1,l-1],min(x[i-1,l],x[i,l-1]))+1;    nf:=trunc(ln(n)/ln(2));    mf:=trunc(ln(m)/ln(2));    for i:=1 to n do    begin        for l:=1 to m do        f[0,0,i,l]:=x[i,l];        for l:=1 to mf do        for j:=1 to m-cf[l]+1 do        f[0,l,i,j]:=max(f[0,l-1,i,j],f[0,l-1,i,j+cf[l-1]]);    end;    for i1:=1 to nf do    for i:=1 to n-cf[i1]+1 do    for l:=0 to mf do    for j:=1 to m-cf[l]+1 do    f[i1,l,i,j]:=max(f[i1-1,l,i,j],f[i1-1,l,i+cf[i1-1],j]);    readln(t);    for i:=1 to t do    begin        readln(x1,y1,x2,y2);        le:=0;        ri:=min(x2-x1,y2-y1)+2;        while le+1<ri do        begin            mi:=(le+ri) div 2;            if ok(mi) then le:=mi            else ri:=mi;        end;        writeln(le);    end;end.
3 0
原创粉丝点击