正解:二分+网络流
解题报告:
这种什么,"同时增加",长得就挺网络流的$QwQ$?然后看到问至少加多少次,于是考虑加个二分呗?于是就大体确定了做题方向,用的网络流+二分
然后就考虑怎么建图呗$QwQ$
首先考虑二分出每个点的值,然后就可以根据这个值求出每个点要增加的多少以及总的修改次数
然后相邻显然考虑黑白染色黑连$S$白连$T$彼此之前连$inf$,跑个最大流判断跑满了没有.
感觉好像要做完辣?
但是这时候要注意到一个问题$QwQ$,就说不能证明这个次数有可二分性$kk$
考虑如果$n\cdot m$为偶数,那显然可二分,因为如果$d$是可行的,那给每个格子都加一就变成了$d+1$显然也可行.
但是如果$n\cdot m$为奇数,发现当$d$可行时并不一定$d+1$可行,,,$QAQ$所以考虑当$n\cdot m$为奇数的时候换一种考虑方法?$QwQ$
考虑设$num_{0/1},sum_{0/1}$表示黑白格的数量和分别的$a$之和,$x$表示最终每个数的值,因为每次一定是一黑一白同时加,所以有$num_{0}\cdot x=sum_{0},num_{1}\cdot x=sum_{1}$,然后可以直接解出$x$然后$check$下就好$QwQ$
$over$!
$upd:$
一周过去我又回来看这题辣,,,$QwQ$
昂说下$T$哪儿了趴
就有个很有效的优化,是在$dinic$中当$flow=0$的时候就可以直接$return$了,,,我挂这儿好多次,,,$QAQ$
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#define int long long
#define gc getchar()
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define n(i) edge[i].nxt
#define ri register int
#define rb register int
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];~i;i=n(i))
const int N=100000+50,M=40+10,inf=(ll)3e15;
int n,m,dep[N],head[N],cur[N],S,T,ed_cnt=-1,l,r,d,a[M][M],sum[2],tot[2],as;
int mvx[4]={0,0,1,-1},mvy[4]={1,-1,0,0};
struct ed{int to,nxt,wei;}edge[N<<1];
il int max(ri x,ri y){return x>y?x:y;}
il int read()
{
rc ch=gc;ri x=0;rb y=1;
while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
if(ch=='-')ch=gc,y=0;
while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
return y?x:-x;
}
il int nam(ri x,ri y){return (x-1)*m+y;}
il void ad(ri x,ri y,ri z)
{edge[++ed_cnt]=(ed){x,head[y],z};head[y]=ed_cnt;edge[++ed_cnt]=(ed){y,head[x],0};head[x]=ed_cnt;}
il bool bfs()
{
queue<int>Q;Q.push(S);memset(dep,0,sizeof(dep));dep[S]=1;
while(!Q.empty())
{
ri nw=Q.front();Q.pop();
e(i,nw)if(w(i) && !dep[t(i)]){dep[t(i)]=dep[nw]+1,Q.push(t(i));if(t(i)==T)return 1;}
}
return 0;
}
il int dfs(ri nw,ri flow)
{
if(nw==T || !flow)return flow;ri ret=0;
for(ri &i=cur[nw];~i;i=n(i))
if(w(i) && dep[t(i)]==dep[nw]+1)
{ri tmp=dfs(t(i),min(flow,w(i)));ret+=tmp,w(i)-=tmp;w(i^1)+=tmp,flow-=tmp;if(!flow)return ret;}
if(!ret)dep[nw]=0;
return ret;
}
il int dinic(){ri ret=0;while(bfs()){rp(i,S,T)cur[i]=head[i];while(int d=dfs(S,inf))ret+=d;}return ret;}
il bool check(ri x)
{
// printf("--- check(%d) ---\n",x);
memset(head,-1,sizeof(head));ed_cnt=-1;ri ret=0;
rp(i,1,n)
{
rp(j,1,m)
{
if((i+j)&1)ad(nam(i,j),S,x-a[i][j]),ret+=x-a[i][j];
else
{
ad(T,nam(i,j),x-a[i][j]);
rp(k,0,3){ri tx=i+mvx[k],ty=j+mvy[k];if(tx && ty && tx<=n && ty<=m)ad(nam(i,j),nam(tx,ty),inf);}
}
}
}
// printf("--- check(%d) ---\n",x);
return dinic()==ret;
}
main()
{
//freopen("5038.in","r",stdin);freopen("5038.out","w",stdout);
ri tmp=read();
while(tmp--)
{
l=0;r=1ll<<35;n=read();m=read();S=0;T=n*m+1;
rp(i,1,n)rp(j,1,m)a[i][j]=read(),l=max(l,a[i][j]);
sum[0]=sum[1]=tot[0]=tot[1]=0;rp(i,1,n)rp(j,1,m)sum[(i+j)&1]+=a[i][j],++tot[(i+j)&1];
if((n*m)&1)
{
ri x=(sum[0]-sum[1])/(tot[0]-tot[1]);
if(check(x))printf("%lld\n",1ll*x*tot[1]-sum[1]);else printf("-1\n");
}
else
{
if(sum[0]!=sum[1] || !check(r)){printf("-1\n");continue;}
while(l<r){ri mid=(l+r)>>1;if(check(mid))r=mid;else l=mid+1;}
printf("%lld\n",l*tot[1]-sum[1]);
}
}
return 0;
}