2756: [SCOI2012]奇怪的游戏

Time Limit: 40 Sec  Memory Limit: 128 MB
Submit: 1594  Solved: 396
[Submit][Status][Discuss]

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

题解:

我们把整个棋盘的格子分为两种,一种为白,一种为黑

然后设最后的格子全部变成了x,那么x*num1-sum1=x*num2-sum2;

其中num1为白色格子数量,num2位黑色格子数量,sum1为白色格子权值和

那么,我们可以得到x=(sum1-sum2)/(num1-num2)

当num1!=num2的时候,我们可以直接通过最大流来check

否则的话,我们就二分枚举答案

首先如果x能够成立的话,那么大与x的所有数都能成立,只要再铺一层就好,而且num1+num2%2==0

所以题目的思路还是比较简单的~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<set>
#include<ctime>
#include<vector>
#include<queue>
#include<algorithm>
#include<map>
#include<cmath>
#define inf (1LL<<50)
#define pa pair<int,int>
#define ll long long
#define p(x,y) (x-1)*m+y
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
ll s0,s1;
int c0,c1;
int test,n,m,cnt,S,T;
int xx[]={,,,-},yy[]={,-,,};
int a[][];
int last[],h[],q[],cur[];
bool color[][];
struct edge{
int to,next;ll v;
}e[];
void insert(int u,int v,ll w)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w;
e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;e[cnt].v=;
}
bool bfs()
{
int head=,tail=;
memset(h,-,sizeof(h));
q[]=S;h[S]=;
while(head!=tail)
{
int now=q[head];head++;
for(int i=last[now];i;i=e[i].next)
if(e[i].v&&h[e[i].to]==-)
{
h[e[i].to]=h[now]+;
q[tail++]=e[i].to;
}
}
return h[T]!=-;
}
ll dfs(int x,ll f)
{
if(x==T)return f;
ll w,used=;
for(int i=cur[x];i;i=e[i].next)
if(h[e[i].to]==h[x]+)
{
w=dfs(e[i].to,min(f-used,e[i].v));
e[i].v-=w;e[i^].v+=w;
if(e[i].v)cur[x]=i;
used+=w;if(used==f)return f;
}
if(!used)h[x]=-;
return used;
}
ll dinic()
{
ll tmp=;
while(bfs())
{
for(int i=S;i<=T;i++)cur[i]=last[i];
tmp+=dfs(S,inf);
}
return tmp;
}
bool check(ll x)
{
memset(last,,sizeof(last));
cnt=;S=;T=n*m+;
ll tot=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(color[i][j])
{
insert(S,p(i,j),x-a[i][j]);tot+=x-a[i][j];
for(int k=;k<;k++)
{
int nowx=i+xx[k],nowy=j+yy[k];
if(nowx<||nowy<||nowx>n||nowy>m)continue;
insert(p(i,j),p(nowx,nowy),inf);
}
}
else insert(p(i,j),T,x-a[i][j]);
if(dinic()==tot)return ;
return ;
}
int main()
{
test=read();
while(test--)
{
c0=c1=s0=s1=;
n=read();m=read();
int mx=;
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
a[i][j]=read(),color[i][j]=(i+j)&;
mx=max(mx,a[i][j]);
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(color[i][j])s1+=a[i][j],c1++;
else s0+=a[i][j],c0++;
if(c0!=c1)
{
ll x=(s0-s1)/(c0-c1);
if(x>=mx)
if(check(x))
{
printf("%lld\n",x*c1-s1);
continue;
}
puts("-1");
}
else
{
ll l=mx,r=inf;
while(l<=r)
{
ll mid=(l+r)>>;
if(check(mid))r=mid-;
else l=mid+;
}
printf("%lld\n",(ll)l*c1-s1);
}
}
return ;
}

BZOJ 2756: [SCOI2012]奇怪的游戏 网络流/二分的更多相关文章

  1. bzoj 2756 [SCOI2012]奇怪的游戏【二分+最大流】

    达成成就:为二分调参 !:多次memset的话要把数组大小开严格一点,否则会T 看到网格图,首先黑白染色. 注意到每次操作都是在一个黑格子和一个白格子上进行的,也就是说,最后黑格子数字和白格子数字和的 ...

  2. BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]

    2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 3352  Solved: 919[Submit][Stat ...

  3. bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流

    2756:[SCOI2012]奇怪的游戏 Time Limit: 40 Sec  Memory Limit: 128 MBSubmit: 4926  Solved: 1362[Submit][Stat ...

  4. bzoj 2756: [SCOI2012]奇怪的游戏

    Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...

  5. BZOJ 2756 SCOI2012 奇怪的游戏 最大流

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2756 Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N ...

  6. BZOJ.2756.[SCOI2012]奇怪的游戏(二分 黑白染色 最大流ISAP)

    题目链接 \(Description\) \(Solution\) 这种题当然要黑白染色.. 两种颜色的格子数可能相同,也可能差1.记\(n1/n2\)为黑/白格子数,\(s1/s2\)为黑/白格子权 ...

  7. bzoj2756: [SCOI2012]奇怪的游戏(网络流+分情况)

    2756: [SCOI2012]奇怪的游戏 题目:传送门 题解: 发现做不出来的大难题一点一个网络流 %大佬 首先黑白染色(原来是套路...)染色之后就可以保证每次操作都一定会使黑白各一个各自的值加1 ...

  8. 洛谷5038 [SCOI2012]奇怪的游戏(二分+网络流+判断奇偶)

    寒假的时候就听过这个题.但是一直没有写. qwq 首先,我们发现题目中的图是个网格图,然后每次可以将相邻两个格子加一. 很容易就想到是黑白染色.那么每次操作,就相当于同时操作一个白点,一个黑点. 我们 ...

  9. BZOJ2756 SCOI2012奇怪的游戏(二分答案+最大流)

    由数据范围容易想到网络流.由于操作只是对于棋盘上相邻两格,容易想到给其黑白染色. 假设已经知道最后要变成什么数.那么给黑白点之间连边,其流量则表示同时增加的次数,再用源汇给其限流为需要增加的数即可. ...

随机推荐

  1. JVM常用启动参数+常用内存调试工具

    一.JVM常用启动参数 -Xms:设置堆的最小值. -Xmx:设置堆的最大值. -Xmn:设置新生代的大小. -Xss:设置每个线程的栈大小. -XX:NewSize:设置新生代的初始值. -XX:M ...

  2. 数论-求n以内的质数

    一.埃拉托斯特尼筛法 名字很高大上,然而并没有什么卵用…… 思路: 在把<=√n的质数所有的<=n的倍数剔除,剩下的就都是质数了,很容易理解…… 复杂度O(nloglogn) #inclu ...

  3. Codeforces 807C - Success Rate(二分枚举)

    题目链接:http://codeforces.com/problemset/problem/807/C 题目大意:给你T组数据,每组有x,y,p,q四个数,x/y是你当前提交正确率,让你求出最少需要再 ...

  4. Django杂记

    django 中 slice 和 truncatewords 不同用法 django中取一段字符串中的前 N 个字符,可以用 slice和truncatewords ,但是两者是有区别的. djang ...

  5. 15 链表中倒数第k个结点

    输入一个链表,输出该链表中倒数第k个结点. p1先走k-1步,p1 p2再一起走 C++: /* struct ListNode { int val; struct ListNode *next; L ...

  6. 《精通Python设计模式》学习结构型之代理模式

    这种模式,总会让人想到SRPING中的AOP, 不同语言有不同的实现方式吧. class SensitiveInfo: def __init__(self): self.users = ['nick' ...

  7. 微信小程序-视频教程-百度云-下载

    链接: https://pan.baidu.com/s/16WGL3whutozx-UXqsDPhhA 提取码: 关注公众号[GitHubCN]回复获取   什么是微信小程序?小程序是一种不需要下载安 ...

  8. input文本框 输入限制三则

    其一,只允许输入数字和小数点. <input onKeypress="return (/[\d.]/.test(String.fromCharCode(event.keyCode))) ...

  9. 继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类。 (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法。 (3)子类中定义的成员变量和父类中定义的成员变量相同时,则父类中的成员变量不能被继承。 (4)子类中定义的成员方法,并且这个方法的名字返回类型,以及参数个数和类型与父类的某个成员方法完全相同,则父类的成员方法不能被继承。 分析以上程

    继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法.(3)子类中定义的成员变量和父类中定义的 ...

  10. CentOS7 之基础设置及常见操作命令

    1.Host SMbus controller not enabled 解决方法: 在 /etc/modprobe.d/blacklist.conf 文件里添加 blacklist i2c_piix4 ...