这道题提醒我,要有将棋盘黑白染色的意识,尤其是看到相邻格子这样的条件的时候,然后就是要用到与其有关的性质与特点以体现其作用,这道题就是用到了黑格子与白格子之间的关系进行的,其出发点是每次一定会给一个黑格子与一个白格子均加一,那么最后黑白格子所加量相同(最关键的地方)。
然后呢,还要观察,最终高度与行动次数一一对应,于是求解他们两个是等效的,然后发现如果最后高度确定,是很好验证是否可行的,就是方格下水道。进一步分析,当黑格与白格的数量不同那么最终高度一定,可以一下判解。当数量相同的时候关于最终高度是单调的,因为h可以,h+1也可以,所以这道题就这么解决了。
为什么我想不到啊(苣蒻++)。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define pos(a,b) (((a)-1)*m+(b))
typedef long long LL;
const int N=;
const int P=N*N;
const int E=P*;
const LL Inf=0x3f3f3f3f3f3f3f3fLL;
struct V{
int to,next;
LL f;
}c[E];
int head[P],t;
inline void add(int x,int y,LL z){
c[++t].to=y,c[t].next=head[x],head[x]=t,c[t].f=z;
}
inline void clear(){
memset(head,,sizeof(head)),t=;
}
int n,m;
int S,T;
int deep[P],q[P],front,back;
inline bool bfs(){
memset(deep,,sizeof(deep));
front=back=,q[back++]=S,deep[S]=;
while(front!=back){
int x=q[front++];
for(int i=head[x];i;i=c[i].next)
if(c[i].f&&deep[c[i].to]==){
deep[c[i].to]=deep[x]+;
if(c[i].to==T)return true;
q[back++]=c[i].to;
}
}return false;
}
inline LL dfs(int x,LL v){
if(x==T||v==)return v;
LL ret=;
for(int i=head[x];i;i=c[i].next)
if(c[i].f&&deep[c[i].to]==deep[x]+){
LL f=dfs(c[i].to,std::min(c[i].f,v));
ret+=f,v-=f,c[i].f-=f,c[i^].f+=f;
if(v==)break;
}
if(ret==)deep[x]=;
return ret;
}
int cnt[];
LL sum[];
int max,val[N][N];
inline LL dinic(){
LL ret=;
while(bfs())ret+=dfs(S,Inf);
return ret;
}
inline bool check(LL ans){
clear();LL ret=;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
if((i+j)&){
if(i>)
add(pos(i,j),pos(i-,j),Inf),add(pos(i-,j),pos(i,j),);
if(j>)
add(pos(i,j),pos(i,j-),Inf),add(pos(i,j-),pos(i,j),);
if(i<n)
add(pos(i,j),pos(i+,j),Inf),add(pos(i+,j),pos(i,j),);
if(j<m)
add(pos(i,j),pos(i,j+),Inf),add(pos(i,j+),pos(i,j),);
add(S,pos(i,j),ans-val[i][j]),add(pos(i,j),S,);
ret+=ans-val[i][j];
}else
add(pos(i,j),T,ans-val[i][j]),add(T,pos(i,j),);
return ret==dinic();
}
inline void work1(){
if((sum[]-sum[])%(cnt[]-cnt[])!=){
puts("-1");return;
}
LL ans=(sum[]-sum[])/(cnt[]-cnt[]);
if(check(ans))
printf("%lld\n",(ans*n*m-(sum[]+sum[]))>>1LL);
else puts("-1");
}
inline void work2(){
if(sum[]!=sum[]){
puts("-1");return;
}
LL l=max,r=Inf/5000LL,mid,ans=;
while(l<=r){
mid=(l+r)>>;
if(check(mid))
ans=mid,r=mid-;
else
l=mid+;
}
if(ans==)puts("-1");
else printf("%lld\n",(ans*n*m-(sum[]+sum[]))>>1LL);
}
int main(){
int test;scanf("%d",&test);
while(test--){
scanf("%d%d",&n,&m);
memset(cnt,,sizeof(cnt));
memset(sum,,sizeof(sum));
max=,S=n*m+,T=n*m+;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j){
scanf("%d",&val[i][j]);
++cnt[(i+j)&],sum[(i+j)&]+=val[i][j];
max=std::max(max,val[i][j]);
}
if(cnt[]!=cnt[])work1();
else work2();
}return ;
}

最新文章

  1. Python自然语言处理工具小结
  2. vm.max_map_count
  3. MySQL 笔记2
  4. [GodLove]Wine93 Tarining Round #4
  5. C++ Primer 5th 第6章 函数
  6. css盒子模型,定位,浮动
  7. Invalid signature file digest for Manifest main attributes
  8. 普实软件:MES机器数据维护
  9. ConstraintLayoutDemo【约束性布局知识梳理】【基于1.1.3】
  10. 【自动化测试】使用Java+selenium填写验证码成功登录
  11. Mongo 应用查询
  12. mysql之表与表关联和表操作
  13. 2018.10.26 bzoj2721: [Violet 5]樱花(数论)
  14. 伪元素::before与::after的用法
  15. Requests中文乱码解决方案
  16. Linux通过FTP上传文件到服务器
  17. 删除CNNIC根证书
  18. [C++] 跨平台的生成GUID方法
  19. HTTP协议Keep-Alive模式详解和HTTP头字段总结
  20. python 之 GIL(线程和进程的应用)

热门文章

  1. php导出excel长数字串显示为科学计数方法与最终解决方法
  2. Failed to read candidate component class错误分析
  3. cf776D Mahmoud and a Dictionary
  4. shell重温---基础篇(参数传递&amp;echo命令)
  5. LeetCode:19. Remove Nth Node From End of List(Medium)
  6. Phoenix映射HBase数据表
  7. 使用USB Key(加密狗)实现身份认证
  8. 如何从海量IP中提取访问最多的10个IP
  9. [网站公告]18:07-18:20阿里云SLB故障造成网站不能正常访问
  10. 平衡二叉树(AVL Tree)