Blinker最近喜欢上一个奇怪的游戏。
这个游戏在一个 \(N \times M\) 的棋盘上玩,每个格子有一个数。每次\(Blinker\)会选择两个相邻的格子,并使这两个数都加上\(1\)。
现在\(Blinker\)想知道最少多少次能使棋盘上的数都变成同一个数,如果永远不能变成同一个数则输出\(-1\)。
输入的第一行是一个整数\(T\),表示输入数据有T轮游戏组成。
每轮游戏的第一行有两个整数\(N\)和\(M\), 分别代表棋盘的行数和列数。 接下来有\(N\)行,每行\(M\)个数。
对于每个游戏输出最少能使游戏结束的次数,如果永远不能变成同一个数则输出\(-1\)。
2
2 2
1 2
2 3
3 3
1 2 3
2 3 4
4 3 2
2
-1
对于\(30%\)的数据,保证\(T<=10,1<=N,M<=8\)
对于\(100%\)的数据,保证 \(T<=10,1<=N,M<=40\),所有数为正整数且小于\(1000000000\)
#include<bits/stdc++.h>
#define LL long long
LL read() {
char ch; LL x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
template<class T> bool chkmax(T &a, const T &b) { return a < b? a = b, 1 : 0; }
template<class T> bool chkmin(T &a, const T &b) { return b < a? a = b, 1 : 0; }
const int maxn = 5e5 + 10;
const LL inf = 9999999999999LL;
struct node {
LL to, can;
node *nxt, *rev;
node(LL to = 0, LL can = 0, node *nxt = NULL): to(to), can(can), nxt(nxt) { rev = NULL; }
}pool[maxn], *tail, *head[maxn], *cur[maxn];
int dep[maxn], n, m, s, t, mp[66][66];
int rx[] = {1, -1, 0, 0};
int ry[] = {0, 0, 1, -1};
void add(int from, int to, LL can) { head[from] = new(tail++) node(to, can, head[from]); }
void link(int from, int to, LL can) {
add(from, to, can), add(to, from, 0LL);
head[from]->rev = head[to]; head[to]->rev = head[from];
}
bool bfs() {
for(int i = s; i <= t; i++) dep[i] = 0, cur[i] = head[i];
std::queue<int> q;
q.push(s); dep[s] = 1;
while(!q.empty()) {
int tp = q.front(); q.pop();
for(node *i = head[tp]; i; i = i->nxt)
if(!dep[i->to] && i->can)
dep[i->to] = dep[tp] + 1, q.push(i->to);
}
return dep[t];
}
LL dfs(int x, LL change) {
if(x == t || !change) return change;
LL flow = 0, ls;
for(node *&i = cur[x]; i; i = i->nxt)
if(dep[i->to] == dep[x] + 1 && (ls = dfs(i->to, std::min(i->can, change)))) {
flow += ls;
change -= ls;
i->can -= ls;
i->rev->can += ls;
if(!change) break;
}
return flow;
}
LL dinic() {
LL flow = 0;
while(bfs()) flow += dfs(s, inf);
return flow;
}
int id(int x, int y) { return (x - 1) * m + y; }
bool ok(LL mid) {
tail = pool;
s = 0, t = n * m + 1;
for(int i = s; i <= t; i++) head[i] = NULL;
LL now = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) {
if((i + j) & 1) {
now += mid - mp[i][j], link(s, id(i, j), mid - mp[i][j]);
for(int k = 0; k < 4; k++) {
int xx = i + rx[k];
int yy = j + ry[k];
if(xx >= 1 && xx <= n && yy >= 1 && yy <= m) link(id(i, j), id(xx, yy), inf);
}
}
else link(id(i, j), t, mid - mp[i][j]);
}
return now == dinic();
}
int main() {
for(int T = read(); T --> 0;) {
n = read(), m = read();
int maxval = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
chkmax(maxval, mp[i][j] = read());
LL tot0 = 0, tot1 = 0, num0 = 0, num1 = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) {
if((i + j) & 1) num1++, tot1 += mp[i][j];
else num0++, tot0 += mp[i][j];
}
if(num0 ^ num1) {
LL endval = (tot0 - tot1) / (num0 - num1);
if(endval >= maxval && ok(endval)) printf("%lld\n", endval * num1 - tot1);
else puts("-1");
}
else {
if(tot0 ^ tot1) puts("-1");
else {
LL l = maxval, r = inf >> 1, ans = r;
while(l <= r) {
LL mid = (l + r) >> 1;
if(ok(mid)) ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%lld\n", ans == inf >> 1? -1 : ans * num1 - tot1);
}
}
}
return 0;
}
原文:https://www.cnblogs.com/olinr/p/10644809.html