bzoj 1047 单调队列

来源:互联网 发布:零基础学java第4版pdf 编辑:程序博客网 时间:2024/05/17 22:18

题意:在a*b的矩阵里,找到一个n*n的子矩阵,使这个子矩阵里的最大值与最小值的差最小

n是固定的,484很像一个固定的窗口在一个面上移动

如果把题目的条件改为一维,

即给定一个序列,窗口长度是n,求这个窗口里最大值与最小值,你会想起什么?

对,没错,就是单调队列

但这是二维怎么破?

拆成一维呀

先对每一行i以它在矩阵里的值为基础,维护两个单调队列f1、g1,分别维护[i,j-n+1]到[i,j]这个窗口的最大值和最小值

再对每一列j以刚才得到的f1、g1为基础,再分别维护两个单调队列f2、g2,分别维护[i-n+1,j]到[i,j]这个窗口的最大值和最小值

这样,最后得到的f2[i,j]、g2[i,j]实际上就是以[i,j]为右下角的n*n的窗口的最大值和最小值

ans=min{f2[i,j]-g2[i,j]} (n<=i<=a,n<=j<=b);

uses math;var        a,b,n,ans       :longint;        i,j             :longint;        map,f,g,f2,g2   :array[0..1510,0..1510] of longint;        que             :array[0..1510] of longint;procedure work1(x:longint);var        j,h,tl:longint;begin   h:=1; tl:=1; que[1]:=1; f[x,1]:=map[x,1];   for j:=2 to b+5 do que[j]:=0;   for j:=2 to b do   begin      while (h<=tl) and (j-que[h]>=n) do inc(h);      f[x,j]:=max(map[x,j],map[x,que[h]]);      while (h<=tl) and (map[x,que[tl]]<=map[x,j]) do dec(tl);      inc(tl); que[tl]:=j;   end;end;procedure work2(x:longint);var        j,h,tl:longint;begin   h:=1; tl:=1; que[1]:=1; g[x,1]:=map[x,1];   for j:=2 to b+5 do que[j]:=0;   for j:=2 to b do   begin      while (h<=tl) and (j-que[h]>=n) do inc(h);      g[x,j]:=min(map[x,j],map[x,que[h]]);      while (h<=tl) and (map[x,que[tl]]>=map[x,j]) do dec(tl);      inc(tl); que[tl]:=j;   end;end;procedure work3(y:longint);var        i,h,tl:longint;begin   h:=1; tl:=1; que[1]:=1; f2[1,y]:=f[1,y];   for i:=2 to a+5 do que[i]:=0;   for i:=2 to a do   begin      while (h<=tl) and (i-que[h]>=n) do inc(h);      f2[i,y]:=max(f[que[h],y],f[i,y]);      while (h<=tl) and (f[que[tl],y]<=f[i,y]) do dec(tl);      inc(tl); que[tl]:=i;   end;end;procedure work4(y:longint);var        i,h,tl:longint;begin   h:=1; tl:=1; que[1]:=1; g2[1,y]:=g[1,y];   for i:=2 to a+5 do que[i]:=0;   for i:=2 to a do   begin      while (h<=tl) and (i-que[h]>=n) do inc(h);      g2[i,y]:=min(g[que[h],y],g[i,y]);      while (h<=tl) and (g[que[tl],y]>=g[i,y]) do dec(tl);      inc(tl); que[tl]:=i;   end;end;begin   //assign(input,'square.in');reset(input);   //assign(output,'square.out');rewrite(output);   read(a,b,n);   for i:=1 to a do     for j:=1 to b do read(map[i,j]);   //   for i:=1 to a do   begin      work1(i); work2(i);   end;   //   for i:=1 to b do   begin      work3(i); work4(i);   end;   //   ans:=maxlongint;   for i:=n to a do      for j:=n to b do ans:=min(ans,f2[i,j]-g2[i,j]);   writeln(ans);   //close(input); close(output);end.

——by Eirlys


0 0