最理想的正方形

题目描述 众所周知,正方形是很美妙的图形。当然了,LJH也很喜欢正方形。
正方形的四条边均相等,四个内角均等于90度,对边分别平行,既是中心对称图形,又是轴对称图形,绕中心旋转90度图形不变。
正方形有这么多美轮美奂的性质,又岂是矩形能比的?所以,当LJH看着一堆矩形时,他心里犯了愁。 “把矩形剪成正方形不就得了。”LJH灵机一动。
当然,LJH既然是处女座,自然不会满足于那些普通的正方形。他要求选出的正方形的四条边都与矩形的边平行,并且边长为n。同时,因为这些矩形是由a*b个自然数组成的,所以LJH希望选出的正方形中,最大值与最小值的差尽量小。他认为这样的正方形很“理想”。
当然了,LJH非常忙(lan),他把任务交给了你,你能帮帮他吗?

输入 第一行3个整数,a,b,n,含义如题目描述。 接下来a行,每行b个自然数,描述一个矩形数阵。

输出 输出只有一个自然数,表示为a*b矩阵中所有n*n正方形区域中的最大整数和最小整数的差的最小值。

样例输入
5 4 2
1 2 5 6
0 17 16 0
16 17 2 1
2 10 2 1
1 2 2 2
样例输出
1
提示
【注释及数据范围】

样例中选取左上角左边为(3,3)或(4,3)的正方形均满足要求。

20%的数据满足a,b<=100,n<=10,时限1s

50%的数据满足a,b<=600,n<=80,时限3s

100%的数据满足,2<=a,b<=2000,n<=a,n<=b,n<=100,所有自然数均不大于10^9,时限5s

读入文件可能很大,c++选手请用scanf读入

由于要求的正方形边长固定,我们可以用单调队列优化,求行的区间最值,求列的区间最值,就可以计算答案了。详见代码。

var
mini,maxn,maxh,minh:array[-100..2000,-100..2000] of longint;
qmax,qmin,tmin,tmax:array[-100..2000] of longint;
lmax,rmax,rmin,lmin,ans,i,j,a,b,n,x:longint;
procedure ins_max(x:longint);
begin
  if tmax[lmax]=0 then inc(lmax)
                  else dec(tmax[lmax]);
  inc(rmax);
  qmax[rmax]:=x;
  while (qmax[rmax]>qmax[rmax-1])and(rmax-1>=lmax) do
  begin
    dec(rmax);
    qmax[rmax]:=qmax[rmax+1];
    tmax[rmax]:=tmax[rmax]+1+tmax[rmax+1];
    tmax[rmax+1]:=0;
  end;
end;

procedure ins_min(x:longint);
begin
  if tmin[lmin]=0 then inc(lmin)
                  else dec(tmin[lmin]);
  inc(rmin);
  qmin[rmin]:=x;
  while (qmin[rmin]<qmin[rmin-1])and(rmin-1>=lmin) do
  begin
    dec(rmin);
    qmin[rmin]:=qmin[rmin+1];
    tmin[rmin]:=tmin[rmin]+1+tmin[rmin+1];
    tmin[rmin+1]:=0;
  end;
end;

procedure ql;
begin
  fillchar(qmin,sizeof(qmin),0);
  fillchar(qmax,sizeof(qmax),0);
  fillchar(tmin,sizeof(tmin),0);
  fillchar(tmax,sizeof(tmax),0);
  qmax[0]:=maxlongint;
  qmin[0]:=-maxlongint;
  lmax:=-n+1; rmax:=0;
  lmin:=-n+1; rmin:=0;
end;

begin
  readln(a,b,n);
  for i:=1 to a do
  begin
    ql;
    for j:=1 to b do
    begin
      read(x);
      ins_max(x);
      ins_min(x);
      if j>=n then
      begin
        maxh[i,j]:=qmax[lmax];
        minh[i,j]:=qmin[lmin];
      end;
    end;
    readln;
  end;
  ans:=maxlongint;
  for i:=n to b do
  begin
    ql;
    for j:=1 to a do
    begin
      ins_max(maxh[j,i]);
      ins_min(minh[j,i]);
      if j>=n then
      begin
        maxn[j,i]:=qmax[lmax];
        mini[j,i]:=qmin[lmin];
        if maxn[j,i]-mini[j,i]<ans then ans:=maxn[j,i]-mini[j,i];
      end;
    end;
  end;
  write(ans);
end.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值