bzoj 2756奇怪的游戏
2756: [SCOI2012]奇怪的游戏
Time Limit: 40 Sec Memory Limit: 128 MB
Description
Blinke 最近喜欢上一个奇怪的游戏。 这个游戏在一个 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\)。
那么如何写\(check(x)\)呢?
首先我们可以将棋盘黑白染色,之后再将黑色与\(T\)相连,将白色与\(S\)相连,再将黑白色之间连接。这样就可以用一个最大流来解决。
因为每个数字都要变为\(x\),所以可以将节点与\(S\)或\(T\)相连的边权设为\(x-val\),之后我们可以将黑白棋子之间的边权设为\(inf\)(其实边权值可以算出,不过由于之前已经限制了边权,所以这里可以不用处理边权)。
因为这个最大流其实就是加了多少次,所以最大流应该等于所有数字与x之差之和的一半。这样,我们就可以写出\(check\)了。
另外,因为\(Cnt[0]*x - Sum[0]=Cnt[1]*x - Sum[1]\),\(Cnt\)表示黑白棋格的个数,\(Sum\)表示黑白棋格各自的和,所以当\(Cnt[0] \neq Cnt[1]\)时,我们可以直接得出\(x\),之后直接\(check(x)\)就好了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MS = 100000, N = 42;
const LL inl = 1LL << 55;
int ina; char inc, inb[1<<16], *ins = inb, *ine = inb; bool insign;
inline char getc() {
if (ins == ine) ine = (ins = inb) + fread(inb, 1, 1 << 16, stdin);
return (ins == ine) ? EOF : *ins++;
}
inline int geti() {
insign = false;
while ((inc = getc()) < '0' || inc > '9') insign |= inc == '-'; ina = inc - '0';
while ((inc = getc()) >= '0' && inc <= '9') ina = (ina << 3) + (ina << 1) + inc - '0';
return insign ? -ina : ina;
}
int mp[N][N], n, m;
bool col[N][N];
LL Sum[2], Num[2], mv;
namespace CC {
int To[MS], Nxt[MS], totE, head[N * N], S, T, d[N * N], dt[N * N];
LL C[MS];
inline void Adde(int a, int b, LL c) {
To[totE] = b; Nxt[totE] = head[a]; C[totE] = c; head[a] = totE++;
To[totE] = a; Nxt[totE] = head[b]; C[totE] = 0; head[b] = totE++;
}
const int dx[] = {0,0,-1,1};
const int dy[] = {1,-1,0,0};
inline int getp(const int &x, const int &y) { return (x-1)*m + y; }
LL dfs(int u, LL flow) {
if (u==T||!flow) return flow;
LL res = 0, t;
for (int i = head[u]; ~i; i = Nxt[i])
if (d[u] == d[To[i]] + 1 && C[i] > 0){
t = dfs(To[i], min(flow, C[i]));
C[i] -= t, C[i^1] += t;
res += t, flow -= t;
if (!flow) return res;
if (d[S] > T) return res;
}
if (!(--dt[d[u]])) d[S] = T + 1;
++dt[++d[u]];
return res;
}
bool check(LL x) {
memset(head, -1, sizeof head); totE = 0;
S = 0, T = getp(n, m) + 1;
LL t, tot = 0, maxflow = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
t = x - mp[i][j];
if (col[i][j]) Adde(getp(i, j), T, t);
else Adde(S, getp(i, j), t);
tot += t;
}
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
for (int k = 0; k < 4; ++k) {
int _i = i + dx[k], _j = j + dy[k];
if (_i < 1 || _i > n || _j < 1 || _j > m) continue;
if (!col[i][j]) Adde(getp(i, j), getp(_i, _j), inl);
}
memset(d, 0, sizeof d); memset(dt, 0, sizeof dt);
dt[0] = T + 1;
while (d[S] < T + 1) maxflow += dfs(S, inl);
return tot == (maxflow << 1);
}
}
void init() {
memset(col, 0, sizeof col);
n = geti(), m = geti();
*Sum = Sum[1] = *Num = Num[1] = mv = 0LL;
bool st = true;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j) {
if ((mp[i][j] = geti()) > mv) mv = mp[i][j];
col[i][j] = !col[i][j-1];
if (j <= 1) col[i][j] = (st = !st);
++Num[col[i][j]]; Sum[col[i][j]] += mp[i][j];
}
}
#define getskip(a) (a*n*m - Sum[0] - Sum[1]) >> 1
void Work() {
if (n * m & 1) {
LL x = Sum[0] - Sum[1];
if (x >= mv && CC::check(x)) printf("%lld\n", getskip(x));
else puts("-1");
} else {
LL l = mv, r = inl / 1000, M, ans = -1;
while (l <= r) {
M = l + r >> 1;
if (CC::check(M)) r = (ans = M) - 1;
else l = M + 1;
}
if (~ans) printf("%lld\n", getskip(ans));
else puts("-1");
}
}
int main() {
for (int T = geti(); T; --T) {
init(); Work();
}
return 0;
}
bzoj 2756奇怪的游戏的更多相关文章
- [BZOJ 2756] 奇怪的游戏
Link:https://www.lydsy.com/JudgeOnline/problem.php?id=2756 Algorithm: 比较新颖的题目 首先发现是对矩阵中相邻两数进行操作 & ...
- BZOJ 2756 奇怪的游戏(最大流)
题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2756 题意:在一个 N*M 的棋盘上玩,每个格子有一个数.每次 选择两个相邻的格子,并使 ...
- 【BZOJ】【2756】【SCOI2012】奇怪的游戏
网络流-最大流 这题……建模部分先略过 这道题是会卡时限的T_T俺的Dinic被卡了,在此放几篇很棒的讲网络流算法的文章,至于大家耳熟能详的论文就不放了…… http://www.cppblog.co ...
- BZOJ 2756: [SCOI2012]奇怪的游戏 [最大流 二分]
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 3352 Solved: 919[Submit][Stat ...
- BZOJ 2756: [SCOI2012]奇怪的游戏 网络流/二分
2756: [SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1594 Solved: 396[Submit][Stat ...
- BZOJ 2756 SCOI2012 奇怪的游戏 最大流
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2756 Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N ...
- bzoj 2756 [SCOI2012]奇怪的游戏 二分+网络流
2756:[SCOI2012]奇怪的游戏 Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 4926 Solved: 1362[Submit][Stat ...
- bzoj 2756: [SCOI2012]奇怪的游戏
Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...
- BZOJ 2756 【SCOI2012】 奇怪的游戏
题目链接:奇怪的游戏 一开始这道题想岔了……想到黑白染色后对总格子数按奇偶性分类讨论,然后没发现奇数个格子的可以直接解方程…… 首先可以发现每次操作是给相邻的两个格子权值加一,因此我们把棋盘黑白染色后 ...
随机推荐
- -bash: ulimit: pipe size: cannot modify limit: Invalid argument
从root账号切换到oracle账号时,出现了"-bash: ulimit: pipe size: cannot modify limit: Invalid argument"提示 ...
- 聊下 git 使用前的一些注意事项
连接方式https.ssh 在使用git的时候,不管你的服务器是开源平台github还是私服gitlab,你都需要clone仓库到本地,这个clone的时候就需要你选择连接方式.这个连接方式决定了你与 ...
- Linux下监控服务器状态命令——top
----------------------------------工作中常用的命令,来判断服务器状态是否正常------------------------------------- top命令作用 ...
- chrome 浏览器的预提取资源机制导致的一个请求发送两次的问题以及ClientAbortException异常
调查一个 pdf 打印报错: ExceptionConverter: org.apache.catalina.connector.ClientAbortException: java.net.Sock ...
- JS导出PDF插件(支持中文、图片使用路径)
在WEB上想做一个导出PDF的功能,发现jsPDF比较多人推荐,遗憾的是不支持中文,最后找到pdfmake,很好地解决了此问题.它的效果可以先到http://pdfmake.org/playgroun ...
- IIS+域组策略+hosts:禁止访问指定网站
一.简介 禁止访问网站可以通过多种方式实现,在网络设备上实现大概是性能最好的方式.本文在域服务器上实现该功能,优点是配置简单.可自定义跳转页面,缺点也很明显,遇到熟悉操作系统的用户,修改hosts文件 ...
- MariaDB的GTID复制和多源复制
什么是GTID? GTID就是全局事务ID(global transaction identifier ),最初由google实现,官方MySQL在5.6才加入该功能.GTID实际上是由UUID+TI ...
- linux init 启动顺序
redhat init大致启动过程 第一个运行的程序是/sbin/init,该文件会读取/etc/inittab文件,并依据此文件来进行初始化工作.比如在设定了运行等级 “:id:3:initdefa ...
- PPK谈JS笔记第一弹
以下内容是读书笔记,再一次温习JS好书:PPK谈JS window.load=initializePageaddEventSimple('window','load',function(){}) lo ...
- [django]用户认证中只允许登陆用户访问(网页安全问题)
当设计一个重要网页时,一般要求未从登陆界面访问的用户不能进入其他页面,那么需要如何设置呢? 如下 django中的url.py urlpatterns = [ url(r'^$', 'login ...