题意:给定一个n*n的矩阵,求一个子矩阵满足权值和属于[k,2*k] (special judge )
思路棒极了(┙>∧<)┙へ┻┻
对一个一维的[l,r],如果这个区间满足 任取x, x<k 且 区间和>=k ,那么答案肯定存在在这个区间中
证明:
因为这个区间里,任意x均满足x<k,所以每加上一个数,区间和的变化量属于[0.k)
所以不会存在一个数,使得一个连续的子区间的区间和加上它以后直接从小于k越过[k,2*k]的区间,瞬间达到大于k
所以只要找到这个[l,r],并从这个区间的左端或右端开始一一删除判断,就可以得到答案的区间
虽然这是一维下的结论,但是这个结论是可以拓展的ヽ(•̀ω•́ )ゝ
即:一个子矩阵满足 任取x,x<k 且 区间和>=k,那么答案肯定存在在这个子矩阵里
所以只要找到这个子矩阵,就可以类比上面的方法删一删就能得到答案的区间,具体:
(1)如果是一行的话,退化成了一维问题,只要从左端或右端开始一一删除判断即可
(2)如果是个子矩阵的话,从最上一行或最下一行一行一行的删除,直到删得还剩一行,按上面的继续处理
然后就是要O(n^2)的找到子矩阵,把大于2*k的点看做障碍点,用悬线法,得到最大子矩阵,一一判断即可
当然,如果一开始读入的时候,如果一个1*1的位置就已经满足[k,2*k],直接输出即可~(~o ̄▽ ̄)~o 。。。
var
n,m :longint;
flag :boolean;
sum,map :array[0..2010,0..2010] of int64;
l,r,h :array[0..2010,0..2010] of longint;
i,j :longint;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
function get_sum(x1,y1,x2,y2:longint):int64;
begin
exit(sum[x2,y2]-sum[x1-1,y2]-sum[x2,y1-1]+sum[x1-1,y1-1]);
end;
function check:boolean;
var
i,j:longint;
begin
for i:=1 to n do
for j:=1 to n do
if (map[i,j]>=m) and (map[i,j]<=2*m) then
begin
writeln(j,' ',i,' ',j,' ',i);
exit(true);
end;
exit(False);
end;
procedure cut(x1,y1,x2,y2:longint);
var
i,j:longint;
begin
while get_sum(x1,y1,x2,y2)>2*m do
begin
if x1=x2 then dec(y2) else
if get_sum(x1+1,y1,x2,y2)>=m then inc(x1) else dec(x2);
end;
flag:=true;
writeln(y1,' ',x1,' ',y2,' ',x2);
end;
begin
read(m,n);
for i:=1 to n do
for j:=1 to n do read(map[i,j]);
if not check then
begin
for i:=1 to n do
for j:=1 to n do sum[i,j]:=map[i,j]+sum[i,j-1]+sum[i-1,j]-sum[i-1,j-1];
for i:=1 to n do
begin
for j:=1 to n do
if (map[i,j]>2*m) then l[i,j]:=0 else l[i,j]:=l[i,j-1]+1;
for j:=n downto 1 do
if (map[i,j]>2*m) then r[i,j]:=0 else r[i,j]:=r[i,j+1]+1;
end;
//
for i:=2 to n do
for j:=1 to n do
if (map[i,j]<=2*m) and (map[i-1,j]<=2*m) then
begin
h[i,j]:=h[i-1,j]+1;
l[i,j]:=min(l[i,j],l[i-1,j]);
r[i,j]:=min(r[i,j],r[i-1,j]);
end;
//
for i:=1 to n do
for j:=1 to n do
if (map[i,j]<=2*m) then
if (get_sum(i-h[i,j],j-l[i,j]+1,i,j+r[i,j]-1)>=m) then
begin
cut(i-h[i,j],j-l[i,j]+1,i,j+r[i,j]-1);break;
end;
if not flag then writeln('NIE');
end;
end.
——by Eirlys