洛谷传送门
BZOJ传送门
题目描述
输入输出格式
输入格式:
第一行两个数 n n n、 m m m,表示矩阵的大小。
接下来 n n n行,每行 m m m列,描述矩阵 A A A。
最后一行两个数 L , R L,R L,R。
输出格式:
第一行,输出最小的答案;
输入输出样例
输入样例#1:
2 2
0 1
2 1
0 1
输出样例#1:
1
说明
对于100%的数据满足 N , M ≤ 200 , 0 ≤ L ≤ R ≤ 1000 , 0 ≤ A i j ≤ 1000 N,M\le 200,0\le L\le R\le 1000,0\le A_{ij}\le 1000 N,M≤200,0≤L≤R≤1000,0≤Aij≤1000
解题分析
考虑如何check一个场面是否合法: 每一行的点向每一列的点连容量为 [ L , R ] [L,R] [L,R]的边, S S S向每一行连流量为当前行元素和的边, 每一列向 T T T连流量为当前列元素和的边, 然后看这个图是否满流。
那么我们直接外面二分答案, 得到每一行, 每一列的上下界, 即可得到答案。
因为边数太多, 需要加当前弧优化。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <queue>
#include <algorithm>
#define INF 1e8
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 505
template <class C>
IN void in(C &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
template <class C> IN C min(C a, C b) {return a < b ? a : b;}
template <class C> IN C max(C a, C b) {return a > b ? a : b;}
int S, T, SS, TT, cnt, n, m, sum, lb, rb;
int head[MX], layer[MX], deg[MX], col[MX], crs[MX], cpy[MX];
struct Edge {int to, fl, nex;} edge[200500];
IN void add(R int from, R int to, R int fl)
{
edge[++cnt] = {to, fl, head[from]}, head[from] = cnt;
edge[++cnt] = {from, 0, head[to]}, head[to] = cnt;
}
namespace Dinic
{
std::queue <int> q;
IN bool BFS(R int st, R int ed)
{
std::memset(layer, 0, sizeof(layer));
layer[st] = 1; R int now; q.push(st);
W (!q.empty())
{
now = q.front(); q.pop();
for (R int i = head[now]; ~i; i = edge[i].nex)
{
if (edge[i].fl && (!layer[edge[i].to]))
layer[edge[i].to] = layer[now] + 1, q.push(edge[i].to);
}
}
return layer[ed];
}
IN int DFS(R int now, R int avai, R int ed)
{
if (now == ed) return avai;
R int lef = avai, buf;
for (int &i = head[now]; ~i; i = edge[i].nex)
{
if (edge[i].fl && layer[edge[i].to] == layer[now] + 1)
{
buf = DFS(edge[i].to, min(edge[i].fl, lef), ed);
if (!buf) continue;
lef -= buf, edge[i].fl -= buf, edge[i ^ 1].fl += buf;
if (!lef) return avai;
}
}
return avai - lef;
}
IN int solve(R int st, R int ed)
{
int ret = 0;
std::memcpy(cpy, head, sizeof(head));
W (BFS(st, ed)) ret += DFS(st, INF, ed), std::memcpy(head, cpy, sizeof(head));
return ret;
}
IN void init()
{
int lef = 0, rig = 2e6, mid, ans;
R int i, j, low, hig;
W (lef <= rig)
{
std::memset(head, cnt = -1, sizeof(head));
std::memset(deg, 0, sizeof(deg));
mid = lef + rig >> 1; sum = 0;
for (R int i = 1; i <= n; ++i)
{
low = max(0, crs[i] - mid);
hig = crs[i] + mid;
deg[S] -= low, deg[i] += low;
add(S, i, hig - low);
for (R int j = 1; j <= m; ++j)
{
deg[i] -= lb, deg[j + n] += lb;
add(i, j + n, rb - lb);
}
}
for (R int i = 1; i <= m; ++i)
{
low = max(0, col[i] - mid);
hig = col[i] + mid;
deg[i + n] -= low, deg[T] += low;
add(i + n, T, hig - low);
}
add(T, S, INF / 2);
for (R int i = S; i <= T; ++i)
{
if (deg[i] > 0) sum += deg[i], add(SS, i, deg[i]);
else if (deg[i] < 0) add(i, TT, -deg[i]);
}
int buf;
if ((buf = solve(SS, TT)) == sum) ans = mid, rig = mid - 1;
else lef = mid + 1;
}
printf("%d", ans);
}
}
int main(void)
{
in(n), in(m); int foo;
S = 0, T = n + m + 1, SS = n + m + 2, TT = n + m + 3;
for (R int i = 1; i <= n; ++i)
for (R int j = 1; j <= m; ++j)
in(foo), col[j] += foo, crs[i] += foo;
in(lb), in(rb);
Dinic::init();
}