bzoj2756 [SCOI2012]奇怪的游戏

Description

Blinker最近喜欢上一个奇怪的游戏。 

这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数。每次 Blinker 会选择两个相邻的格子,并使这两个数都加上 1。 

现在 Blinker 想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出-1。 

Input

输入的第一行是一个整数T,表示输入数据有T轮游戏组成。 
每轮游戏的第一行有两个整数N和M, 分别代表棋盘的行数和列数。 
接下来有N行,每行 M个数。 

Output

  对于每个游戏输出最少能使游戏结束的次数,如果永远不能变成同一个数则输出-1。

Sample Input

2
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2

Sample Output

2
-1

HINT

【数据范围】 

对于30%的数据,保证  T<=10,1<=N,M<=8 
对于100%的数据,保证  T<=10,1<=N,M<=40,所有数为正整数且小于1000000000 

 

正解:二分+最大流。

这道题还是很不容易想啊,不过我写了个骗分居然有$90$分。。

首先我们肯定是要黑白染色,相邻的点染不同的颜色。

然后我们按照格子数分奇偶讨论:

如果格子数为偶数,那么黑点和白点个数相同,于是所有黑点的和与所有白点的和必须相同,否则一定不合法。

因为当黑点和白点个数相同时,每个点的权值$+1$,等价于将相邻的上下两点匹配一次,所以我们发现每个点的最终权值是满足单调性的。也就是说如果$v$合法,那么$v+1$也一定合法,于是我们直接二分最终的权值,建图跑最大流就行了。

当格子数为奇数时,黑点与白点个数不同。那么我们可以直接算出最终每个格子的权值。

由$v*num_{black}-sum_{black}=v*num_{white}-sum_{white}$,解得$v=(sum_{black}-sum_{while})/(num_{black}-num_{white})$。

$num$为格子数量,$sum$为初始的格子权值和。

那么我们判断一下$v$是否合法就行了。

 

  1 #include <bits/stdc++.h>
  2 #define il inline
  3 #define RG register
  4 #define ll long long
  5 #define inf (1LL<<60)
  6 #define N (1000010)
  7 #define pos(i,j) ((i-1)*m+j)
  8 
  9 using namespace std;
 10 
 11 struct edge{ int nt,to; ll flow,cap; }g[N<<1];
 12 
 13 int head[N],d[N],q[N],a[42][42],S,T,n,m,num,tot;
 14 ll x,y,ans;
 15 
 16 il int gi(){
 17   RG int x=0,q=1; RG char ch=getchar();
 18   while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
 19   if (ch=='-') q=-1,ch=getchar();
 20   while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar();
 21   return q*x;
 22 }
 23 
 24 il void insert(RG int from,RG int to,RG ll cap){
 25   g[++num]=(edge){head[from],to,0,cap},head[from]=num; return;
 26 }
 27 
 28 il int bfs(RG int S,RG int T){
 29   for (RG int i=1;i<=T;++i) d[i]=0;
 30   RG int h=0,t=1; q[t]=S,d[S]=1;
 31   while (h<t){
 32     RG int x=q[++h],v;
 33     for (RG int i=head[x];i;i=g[i].nt){
 34       v=g[i].to;
 35       if (!d[v] && g[i].cap>g[i].flow){
 36     d[v]=d[x]+1,q[++t]=v;
 37     if (v==T) return 1;
 38       }
 39     }
 40   }
 41   return d[T];
 42 }
 43 
 44 il ll dfs(RG int x,RG int T,RG ll a){
 45   if (!a || x==T) return a; RG ll flow=0,f; RG int v;
 46   for (RG int i=head[x];i;i=g[i].nt){
 47     v=g[i].to;
 48     if (d[v]==d[x]+1 && g[i].cap>g[i].flow){
 49       f=dfs(v,T,min(a,g[i].cap-g[i].flow));
 50       if (!f){ d[v]=0; continue; }
 51       g[i].flow+=f,g[i^1].flow-=f;
 52       flow+=f,a-=f; if (!a) return flow;
 53     }
 54   }
 55   return flow;
 56 }
 57 
 58 il ll maxflow(RG int S,RG int T){
 59   RG ll flow=0;
 60   while (bfs(S,T)) flow+=dfs(S,T,inf);
 61   return flow;
 62 }
 63 
 64 il int check(RG ll key){
 65   for (RG int i=1;i<=T;++i) head[i]=0; num=1;
 66   for (RG int i=1;i<=n;++i)
 67     for (RG int j=1;j<=m;++j){
 68     if ((i+j)&1) insert(S,pos(i,j),key-a[i][j]),insert(pos(i,j),S,0);
 69     else insert(pos(i,j),T,key-a[i][j]),insert(T,pos(i,j),0);
 70     }
 71   for (RG int i=1;i<=n;++i)
 72     for (RG int j=1;j<=m;++j)
 73       if ((i+j)&1){
 74     if (i>1) insert(pos(i,j),pos(i-1,j),inf),insert(pos(i-1,j),pos(i,j),0);
 75     if (i<n) insert(pos(i,j),pos(i+1,j),inf),insert(pos(i+1,j),pos(i,j),0);
 76     if (j>1) insert(pos(i,j),pos(i,j-1),inf),insert(pos(i,j-1),pos(i,j),0);
 77     if (j<m) insert(pos(i,j),pos(i,j+1),inf),insert(pos(i,j+1),pos(i,j),0);
 78       }
 79   maxflow(S,T);
 80   for (RG int i=1,k=2;i<=n;++i)
 81     for (RG int j=1;j<=m;++j,k+=2)
 82       if (g[k].flow!=g[k].cap) return 0;
 83   return 1;
 84 }
 85 
 86 il void work(){
 87   n=gi(),m=gi(),tot=x=y=0,S=n*m+1,T=S+1;
 88   for (RG int i=1;i<=n;++i)
 89     for (RG int j=1;j<=m;++j){
 90       a[i][j]=gi(),tot=max(tot,a[i][j]);
 91       if ((i+j)&1) x+=a[i][j]; else y+=a[i][j];
 92     }
 93   if (n*m%2==0){
 94     if (x!=y){ puts("-1"); return; }
 95     RG ll l=tot,r=1LL<<50,mid;
 96     while (l<=r){
 97       mid=(l+r)>>1;
 98       if (check(mid)) ans=mid,r=mid-1; else l=mid+1;
 99     }
100     printf("%lld\n",(ans*n*m>>1)-x);
101   } else{
102     RG ll X=y-x; if (X<tot){ puts("-1"); return; }
103     if (check(X)) printf("%lld\n",X*((n*m)>>1)-x);
104     else puts("-1");
105   }
106   return;
107 }
108 
109 int main(){
110 #ifndef ONLINE_JUDGE
111   freopen("game.in","r",stdin);
112   freopen("game.out","w",stdout);
113 #endif
114   RG int T=gi();
115   while (T--) work();
116   return 0;
117 }

 

posted @ 2017-08-15 17:21  wfj_2048  阅读(148)  评论(0编辑  收藏  举报