bzoj 1127 贪心+悬线法

来源:互联网 发布:634741网络语什么意思 编辑:程序博客网 时间:2024/06/06 06:47

题意:给定一个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



0 0
原创粉丝点击