\(\mathcal{Description}\)

  Link.

  给定一个 \(n\times m\) 的矩阵 \(A\),构造一个 \(n\times m\) 的矩阵 \(B\),s.t. \((\forall i\in[1,n],j\in[1,m])(b_{ij}\in[L,R])\),且最小化:

\[\max\left\{\max_{i=1}^n\{\left|\sum_{j=1}^m a_{ij}-b_{ij}\right|,\max_{j=1}^m\left| \sum_{i=1}^n a_{ij}-b_{ij} \right|\right\}
\]

  输出上式最小值即可。

  \(n,m\le200\),\(0\le L,R,a_{ij}\le10^3\)。

\(\mathcal{Solution}\)

  不难想到二分答案。记 \(r_i=\sum_{j=1}^m a_{ij}\),\(c_i=\sum_{j=1}^n a_{ji}\),设当前答案为 \(x\),则第 \(i\) 行的取值区间为 \([\max\{0,r_i-x\},r_i+x]\),第 \(i\) 列的取值区间为 \([\max\{0,c_i-x\},c_i+x]\),然后 \(B\) 的每个元素又有限制 \([L,R]\),所以猜测可以通过求上下界可行流来构造 \(B\):

  • \(S\) 连向 \(n\) 个行虚点 \(r_1,r_2,\cdots,r_n\),流量区间如上;
  • 行虚点 \(r_i\) 连向第 \(i\) 行元素入点 \(bi_{ij}\),流量无限制;
  • 元素入点 \(bi_{ij}\) 连向元素出点 \(bo_{ij}\),流量区间 \([L,R]\);
  • 元素出点 \(bo_{ij}\) 连向列虚点 \(c_j\),流量无限制;
  • \(m\) 个列虚点 \(c_1,c_2,\cdots,c_m\) 连向 \(T\),流量区间如上。

  求这个有源汇流网络是否存在可行流即可判断 \(x\) 是否合法。

  复杂度 \(\mathcal O(\log(nR)D)\),其中 \(D\) 为这种分层图下 Dinic 算法的复杂度。

\(\mathcal{Code}\)

/* Clearink */

#include <queue>
#include <cstdio> const int MAXN = 300, MAXV = 1e3, MAXND = MAXN * ( MAXN + 1 ) * 2 + 2, INF = 0x3f3f3f3f;
int n, m, L, R, rsum[MAXN + 5], csum[MAXN + 5], deg[MAXND + 5]; inline int imin ( const int a, const int b ) { return a < b ? a : b; }
inline int imax ( const int a, const int b ) { return a < b ? b : a; } struct MaxFlowGraph {
static const int MAXND = ::MAXND + 2, MAXEG = MAXN * MAXN * 3 + MAXN * 2;
int ecnt, head[MAXND + 5], S, T, bound, curh[MAXND + 5], d[MAXND + 5];
struct Edge { int to, flow, nxt; } graph[MAXEG * 2 + 5]; inline void clear () {
ecnt = 1;
for ( int i = 0; i <= bound; ++i ) head[i] = 0;
} inline void link ( const int s, const int t, const int f ) {
graph[++ecnt] = { t, f, head[s] };
head[s] = ecnt;
} inline Edge& operator [] ( const int k ) { return graph[k]; } inline void operator () ( const int s, const int t, const int f ) {
#ifdef RYBY
printf ( "%d %d ", s, t );
if ( f == INF ) puts ( "INF" );
else printf ( "%d\n", f );
#endif
link ( s, t, f ), link ( t, s, 0 );
} inline bool bfs () {
static std::queue<int> que;
for ( int i = 0; i <= bound; ++i ) d[i] = -1;
d[S] = 0, que.push ( S );
while ( !que.empty () ) {
int u = que.front (); que.pop ();
for ( int i = head[u], v; i; i = graph[i].nxt ) {
if ( graph[i].flow && !~d[v = graph[i].to] ) {
d[v] = d[u] + 1;
que.push ( v );
}
}
}
return ~d[T];
} inline int dfs ( const int u, const int iflow ) {
if ( u == T ) return iflow;
int ret = 0;
for ( int& i = curh[u], v; i; i = graph[i].nxt ) {
if ( graph[i].flow && d[v = graph[i].to] == d[u] + 1 ) {
int oflow = dfs ( v, imin ( iflow - ret, graph[i].flow ) );
ret += oflow, graph[i].flow -= oflow, graph[i ^ 1].flow += oflow;
if ( ret == iflow ) break;
}
}
if ( !ret ) d[u] = -1;
return ret;
} inline int calc ( const int s, const int t ) {
S = s, T = t;
int ret = 0;
for ( ; bfs (); ret += dfs ( S, INF ) ) {
for ( int i = 0; i <= bound; ++i ) curh[i] = head[i];
}
return ret;
}
} graph; inline bool check ( const int lim ) {
int cnt = n * m * 2;
graph.bound = cnt + n + m + 3;
graph.clear (), graph.S = cnt + n + m + 2, graph.T = graph.S + 1;
int rS = 0, rT = cnt + n + m + 1;
for ( int i = 0; i <= graph.bound; ++i ) deg[i] = 0;
for ( int i = 1; i <= n; ++i ) { // row.
int lw = imax ( 0, rsum[i] - lim ), up = rsum[i] + lim;
deg[rS] -= lw, deg[cnt + i] += lw;
graph ( rS, cnt + i, up - lw );
}
for ( int i = 1; i <= m; ++i ) { // col.
int lw = imax ( 0, csum[i] - lim ), up = csum[i] + lim;
deg[cnt + n + i] -= lw, deg[rT] += lw;
graph ( cnt + n + i, rT, up - lw );
}
for ( int i = 1; i <= n; ++i ) {
for ( int j = 1; j <= m; ++j ) {
int id = ( i - 1 ) * m + j, rid = id + n * m;
deg[id] -= L, deg[rid] += L;
graph ( id, rid, R - L );
graph ( cnt + i, id, INF ), graph ( rid, cnt + n + j, INF );
}
}
int req = 0;
for ( int i = rS; i <= rT; ++i ) {
if ( deg[i] > 0 ) graph ( graph.S, i, deg[i] );
else if ( deg[i] ) req -= deg[i], graph ( i, graph.T, -deg[i] );
}
graph ( rT, rS, INF );
return graph.calc ( graph.S, graph.T ) == req;
} int main () {
scanf ( "%d %d", &n, &m );
for ( int i = 1; i <= n; ++i ) {
for ( int j = 1, a; j <= m; ++j ) {
scanf ( "%d", &a );
rsum[i] += a, csum[j] += a;
}
}
scanf ( "%d %d", &L, &R );
int l = 0, r = imax ( n, m ) * R;
while ( l < r ) {
int mid = l + r >> 1;
if ( check ( mid ) ) r = mid;
else l = mid + 1;
}
printf ( "%d\n", l );
return 0;
}

Solution -「洛谷 P4194」矩阵的更多相关文章

  1. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  2. Note/Solution -「洛谷 P5158」「模板」多项式快速插值

    \(\mathcal{Description}\)   Link.   给定 \(n\) 个点 \((x_i,y_i)\),求一个不超过 \(n-1\) 次的多项式 \(f(x)\),使得 \(f(x ...

  3. Solution -「洛谷 P4719」「模板」"动态 DP" & 动态树分治

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个结点的带权树,\(m\) 次单点点权修改,求出每次修改后的带权最大独立集.   \(n,m\le10^5 ...

  4. Solution -「洛谷 P4198」楼房重建

    \(\mathcal{Description}\)   Link.   给定点集 \(\{P_n\}\),\(P_i=(i,h_i)\),\(m\) 次修改,每次修改某个 \(h_i\),在每次修改后 ...

  5. Solution -「洛谷 P6577」「模板」二分图最大权完美匹配

    \(\mathcal{Description}\)   Link.   给定二分图 \(G=(V=X\cup Y,E)\),\(|X|=|Y|=n\),边 \((u,v)\in E\) 有权 \(w( ...

  6. Solution -「洛谷 P6021」洪水

    \(\mathcal{Description}\)   Link.   给定一棵 \(n\) 个点的带点权树,删除 \(u\) 点的代价是该点点权 \(a_u\).\(m\) 次操作: 修改单点点权. ...

  7. Solution -「洛谷 P5236」「模板」静态仙人掌

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的仙人掌,\(q\) 组询问两点最短路.   \(n,q\le10^4\),\(m\ ...

  8. Solution -「洛谷 P4320」道路相遇

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的连通无向图,并给出 \(q\) 个点对 \((u,v)\),询问 \(u\) 到 ...

  9. Solution -「洛谷 P5827」边双连通图计数

    \(\mathcal{Description}\)   link.   求包含 \(n\) 个点的边双连通图的个数.   \(n\le10^5\). \(\mathcal{Solution}\)    ...

随机推荐

  1. Presto 在字节跳动的内部实践与优化

    在字节跳动内部,Presto 主要支撑了 Ad-hoc 查询.BI 可视化分析.近实时查询分析等场景,日查询量接近 100 万条.本文是字节跳动数据平台 Presto 团队-软件工程师常鹏飞在 Pre ...

  2. MINItest软件架构总结

    MINItest软件架构总结 ----helloWen MINItest软件架构总结1. Problem Description2. Analysis3. Solution3.1. 通过读取设备信息来 ...

  3. access偏移注入原理

    前言:近段时间在学习access偏移注入时,在网上查询了大量的资料,感觉很多资料讲解的十分模糊并且我个人认为有很多不够严谨的地方,于是我便在线下经过大量测试,写出以下文章,如有错误,望指出. 如要转载 ...

  4. 干货 | Dart 并发机制详解

    Dart 通过 async-await.isolate 以及一些异步类型概念 (例如 Future 和 Stream) 支持了并发代码编程.本篇文章会对 async-await.Future 和 St ...

  5. 【经验总结】VSCode中找不到numpy/matplotlib/pillow,navigator没了

    在VSCode中写python时,import numpy和matplotlib总是报错找不到模块,用conda list和pip list看到都安装了numpy,前后折腾了很久遇到了好几个问题: 无 ...

  6. LINUX系统机器人

    简介 在2016年,国内的软硬件尚不能有效支撑我们制造智能机器人,我们无法有效在Linux进行语音唤醒,只能使用斯坦福大学狮身人面像语音开源项目来进行英文识别我们对RIMA的呼唤,抗干扰性为0,意味着 ...

  7. 【HarmonyOS】【JS】鸿蒙Js camera怎么拍照并使用image显示出来

    官网中有描述camera组件功能界面属性介绍,但是官网没有具体的demo让我们感受拍照的功能,今天写一篇demo来完善一下拍照的功能 demo 功能如下 第一步首先进行拍照功能 第二步 进行js页面跳 ...

  8. Redis持久化----RDB和AOF 的区别

    关于Redis说点什么,目前都是使用Redis作为数据缓存,缓存的目标主要是那些需要经常访问的数据,或计算复杂而耗时的数据.缓存的效果就是减少了数据库读的次数,减少了复杂数据的计算次数,从而提高了服务 ...

  9. memcached 小记

    Memcached是一个自由开源的,高性能,分布式内存对象缓存系统. Memcached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串.对象).这些数据可以是数据库调用.API ...

  10. Vue3 框架基础随笔 (一)

    VUE框架基础部分随笔 Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架. Vue可以使用简单的代码实现一个单页面应用. 基本格式 Vue通过模板语法来声明式的将数 ...