看到相邻格子都+1的操作一下就想到黑白染色了
相邻格子都+1说明不管怎么弄,黑格子的总和和白格子总和的差总是定值
这里首先要注意,最后不一定变成的是所有元素中的最大值,可能比它大
比如 1 2 2
2 1 0 这里最后可以全变成3
所以做题的时候下结论一定要小心,我们不妨设最后都变成了x,c1,c2表示黑白格子个数,s1,s2分别表示原来黑白格子元素和
则x*c1-s1=x*c2-s2
则(c1-c2)*x=s1-s2
如果棋盘格子数为奇数,则,最后一定变成(s1-s2)/(c1-c2),我们只要验证这个即可
否则,当s1≠s2则无解
等于的话就有许多解,随着x的增大显然操作次数增多,所以我们二分x判定
如何判定呢?
我们将s连黑点,白点连t,流量是x-初始值
对相邻黑白点连inf的边,表示这两个格子可以共同+1
最后我们只要判断是否满流即可
1 const inf=int64(1) shl 36; 2 dx:array[1..4] of longint=(0,0,-1,1); 3 dy:array[1..4] of longint=(1,-1,0,0); 4 5 type node=record 6 next,po:longint; 7 flow:int64; 8 end; 9 10 var e:array[0..400010] of node; 11 p,cur,pre,numh,h:array[0..1640] of longint; 12 d:array[0..1640] of int64; 13 num:array[0..40,0..40] of longint; 14 a:array[0..40,0..40] of int64; 15 test,t,i,n,m,j,k,len:longint; 16 ans,mx,s1,s2,l,r,mid:int64; 17 18 function min(a,b:int64):int64; 19 begin 20 if a>b then exit(b) else exit(a); 21 end; 22 23 procedure add(x,y:longint;f:int64); 24 begin 25 inc(len); 26 e[len].po:=y; 27 e[len].flow:=f; 28 e[len].next:=p[x]; 29 p[x]:=len; 30 end; 31 32 procedure build(x,y:longint;f:int64); 33 begin 34 add(x,y,f); 35 add(y,x,0); 36 end; 37 38 function sap:int64; 39 var u,i,j,tmp,q:longint; 40 neck:int64; 41 42 begin 43 fillchar(h,sizeof(h),0); 44 fillchar(numh,sizeof(numh),0); 45 for i:=0 to t do 46 cur[i]:=p[i]; 47 neck:=inf; 48 numh[0]:=t+1; 49 u:=0; 50 sap:=0; 51 while h[0]<t+1 do 52 begin 53 d[u]:=neck; 54 i:=cur[u]; 55 while i<>-1 do 56 begin 57 j:=e[i].po; 58 if (e[i].flow>0) and (h[u]=h[j]+1) then 59 begin 60 neck:=min(neck,e[i].flow); 61 cur[u]:=i; 62 pre[j]:=u; 63 u:=j; 64 if u=t then 65 begin 66 sap:=sap+neck; 67 while u<>0 do 68 begin 69 u:=pre[u]; 70 j:=cur[u]; 71 dec(e[j].flow,neck); 72 inc(e[j xor 1].flow,neck); 73 end; 74 neck:=inf; 75 end; 76 break; 77 end; 78 i:=e[i].next; 79 end; 80 if i=-1 then 81 begin 82 dec(numh[h[u]]); 83 if numh[h[u]]=0 then exit; 84 q:=-1; 85 tmp:=t; 86 i:=p[u]; 87 while i<>-1 do 88 begin 89 j:=e[i].po; 90 if (e[i].flow>0) and (h[j]<tmp) then 91 begin 92 tmp:=h[j]; 93 q:=i; 94 end; 95 i:=e[i].next; 96 end; 97 cur[u]:=q; 98 h[u]:=tmp+1; 99 inc(numh[h[u]]); 100 if u<>0 then 101 begin 102 u:=pre[u]; 103 neck:=d[u]; 104 end; 105 end; 106 end; 107 end; 108 109 function check(w:int64):boolean; 110 var i,j,x,y:longint; 111 s:int64; 112 begin 113 len:=-1; 114 s:=0; 115 fillchar(p,sizeof(p),255); 116 for i:=1 to n do 117 for j:=1 to m do 118 if (i+j) mod 2=1 then build(num[i,j],t,w-a[i,j]) 119 else begin 120 build(0,num[i,j],w-a[i,j]); 121 for k:=1 to 4 do 122 begin 123 x:=i+dx[k]; 124 y:=j+dy[k]; 125 if num[x,y]>0 then build(num[i,j],num[x,y],inf); 126 end; 127 s:=s+w-a[i,j]; 128 end; 129 130 if sap<>s then exit(false) 131 else begin 132 ans:=s; 133 exit(true); 134 end; 135 end; 136 137 begin 138 readln(test); 139 while test>0 do 140 begin 141 dec(test); 142 readln(n,m); 143 fillchar(num,sizeof(num),0); 144 s1:=0; 145 s2:=0; 146 k:=0; 147 mx:=0; 148 for i:=1 to n do 149 for j:=1 to m do 150 begin 151 read(a[i,j]); 152 inc(k); 153 num[i,j]:=k; 154 if (i+j) mod 2=0 then s1:=s1+a[i,j] 155 else s2:=s2+a[i,j]; 156 if a[i,j]>mx then mx:=a[i,j]; 157 end; 158 t:=n*m+1; 159 ans:=-1; 160 if n*m mod 2=1 then 161 begin 162 if (mx<=s1-s2) and check(s1-s2) then writeln(ans) 163 else writeln(-1); 164 end 165 else begin 166 if s1<>s2 then writeln(-1) 167 else begin 168 l:=mx; 169 r:=int64(1) shl 33; 170 while l<=r do 171 begin 172 mid:=(l+r) shr 1; 173 if check(mid) then r:=mid-1 174 else l:=mid+1; 175 end; 176 writeln(ans); 177 end; 178 end; 179 end; 180 end. 181 182