首页 > 其他分享 >题解 //「BZOJ2406」矩阵

题解 //「BZOJ2406」矩阵

时间:2023-07-20 15:03:13浏览次数:43  
标签:return int 题解 BZOJ2406 矩阵 dep add maxn gs

赛时公告

现在呢?:现在有弹窗了吗 「2023-07-19 16:45:07」

此时无声胜有声。

F.「BZOJ2406」矩阵

http://222.180.160.110:1024/contest/3825/problem/7

这是头一次见识到把矩阵和网络流结合在一起的题目。不过这种处理方式也是我们在学习二分图时的常客了:把行和列连边表示某一元素。

我们发现 \(B_{i, j}\) 有给定的上下界,故我们考虑 上下界网络流。那怎么去表示 \(B_{i, j}\) 呢?这就要联系到我们刚刚说过的连边方式:用边 \(i\to j\) 的流量来表示 \(B_{i, j}\),有 \([L, R]\) 的上下界。

可是我们除了 \([L,R]\) 的限制,还有最大值这个条件呀,怎么办呢?

注意到题目要求最大的最小,自然想到二分答案。设答案为 \(x\),则我们需要保证每行每列的答案都 \(\le x\)。每行每列,这刚好是我们的建点方式。这对点本身作出了要求,这套路我们熟,让大源点向行连边、列向大汇点连边就好。

那么这些边的上下界怎么办呢?我们已知 \(|S_A-S_B|\le x\),那么变形得:

\[\begin{cases} S_B\ge S_A-x &(S_B \le S_A) \\\\ S_B\le S_A+x &(S_B \ge S_A) \end{cases} \]

照理来说,两行的符号相反,我们现在已经得到了一个具有对称美的上下界:\(S_A-x\le S_B\le S_A+x\),就应该速速连边了,可是我怎么看都觉得不舒坦:这个不等式可是带条件的,就这么直接拿来做上下界真的没问题吗?

答案是没问题,因为我看的题解是这么写的 本着探索求真精神,我们考虑尊重原不等式(因为原不等式的每一行刚好也有两个相反的符号),将这些边拆成两条,一条的上下界是 \([S_A-x, S_A]\),另一条是 \([S_A,S_A+x]\)。6。我明白题解为什么这么写了,一个的下界就是另一个的上界,那直接合并不就行了,这个 naive trick 题解都不屑于写出来。

然后跑个可行流就可以了。注意要保证边的下界为非负。

#define int long long
namespace XSC062 {
using namespace fastIO;
const int lim = 2e5;
const int maxn = 405;
const int inf = 1e18;
const int maxm = 3e5 + 5;
struct _ {
	int v, w, n;
	_() {}
	_(int v1, int w1, int n1) {
		v = v1, w = w1, n = n1;
	}
};
_ u[maxm];
int gs, gt, tot;
int a[maxn][maxn];
int l, mid, r, res;
int h[maxn], dif[maxn];
int n, m, cnt, s, t, L, R;
int vis[maxn], now[maxn], dep[maxn];
inline int max(int x, int y) {
	return x > y ? x : y;
}
inline int min(int x, int y) {
	return x < y ? x : y;
}
bool BFS(int n) {
	std::fill(vis + 1, vis + n + 1, 0);
	std::fill(dep + 1, dep + n + 1, 0); 
	std::queue<int> q;
	dep[gs] = 1, vis[gs] = 1;
	q.push(gs), now[gs] = h[gs];
	while (!q.empty()) {
		int f = q.front();
		q.pop();
		for (int i = h[f]; i; i = u[i].n) {
			int v = u[i].v, w = u[i].w;
			if (vis[v] == 1 || w == 0)
				continue;
			vis[v] = 1, now[v] = h[v];
			dep[v] = dep[f] + 1, q.push(v);
			if (v == gt)
				return 1;
		}
	}
	return 0;
}
int findP(int x, int flow = inf) {
	if (x == gt)
		return flow;
	int rest = flow, i;
	for (i = now[x]; rest && i; i = u[i].n) {
		now[x] = i;
		int v = u[i].v, w = u[i].w;
		if (dep[v] != dep[x] + 1 || w == 0)
			continue;
		int t = findP(v, min(rest, w));
		if (t == 0)
			dep[v] = 0;
		rest -= t;
		u[i].w -= t, u[i ^ 1].w += t;
	}
	return flow - rest;
}
inline int Dinic(int n) {
	int res = 0;
	while (BFS(n)) {
		int t = findP(gs);
		while (t) {
			res += t;
			t = findP(gs);
		}
	}
	return res;
}
inline void add(int x, int y, int w) {
	u[++tot] = _(y, w, h[x]);
	h[x] = tot;
	return;
}
inline void add(int x, int y, int d, int u) {
	add(x, y, u - d), add(y, x, 0);
	dif[x] -= d, dif[y] += d;
	return;
}
inline void Init(void) {
	tot = 1, cnt = 0;
	memset(h, 0, sizeof (h));
	memset(dif, 0, sizeof (dif));
	return;
}
bool check(int x) {
	Init();
	s = n + m + 1, t = s + 1;
	add(t, s, inf), add(s, t, 0);
	gs = t + 1, gt = t + 2;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j)
			add(i, j + n, L, R);
	}
	for (int i = 1; i <= n; ++i) {
		int sum = 0;
		for (int j = 1; j <= m; ++j)
			sum += a[i][j];
		add(s, i, max(0, sum - x), sum + x);
	}
	for (int j = 1; j <= m; ++j) {
		int sum = 0;
		for (int i = 1; i <= n; ++i)
			sum += a[i][j];
		add(j + n, t, max(sum - x, 0), sum + x);
	}
	for (int i = 1; i <= t; ++i) {
		if (dif[i] < 0) {
			add(i, gt, -dif[i]);
			add(gt, i, 0);
		}
		else if (dif[i] > 0) {
			add(gs, i, dif[i]);
			add(i, gs, 0);
			cnt += dif[i];
		}
	}
	return (Dinic(gt) == cnt);
}
int main() {
	read(n), read(m);
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j)
			read(a[i][j]);
	}
	read(L), read(R);
	l = 0, r = lim, res = -1029;
	while (l <= r) {
		mid = (l + r) >> 1;
		if (check(mid)) {
			res = mid;
			r = mid - 1;
		}
		else l = mid + 1;
	}
	print(res);
	return 0;
}
} // namespace XSC062
#undef int

你最好有要事相求.jpg

标签:return,int,题解,BZOJ2406,矩阵,dep,add,maxn,gs
From: https://www.cnblogs.com/XSC062/p/17568422.html

相关文章

  • 【题解】Luogu[P3360] 偷天换日
    solution开题显然是个树形dp,只不过在树形dp上又增加了背包问题。我们不妨将每个走廊看成一个点,把交叉口看成边(当然也可以把交叉口看成点,不过写起来麻烦一些),于是就转化为了一棵二叉树。我们设\(f_{i,j}\)表示以\(i\)为根的子树内,花费了不超过\(j\)时间,能拿到的最大价值......
  • Frog 3 题解
    Frog3题目大意题意都这么明确了还要这个干什么。存在\(n\)个点,每个点有一个属性\(h_i\),\(h_i\)单增,从点\(i\)移动到点\(j(j>i)\)的代价是\((h_i-h_j)^2+C\),其中\(C\)是给定的常数,求从点\(1\)移动到点\(n\)的最小代价。思路分析斜率优化DP板题。设\(f_i\)......
  • SP10582 题解
    题目链接题意简述给定一个有\(n\)个数的数组,求从第一个数字开始,向后每\(k\)个数字的最大值。题目分析看到没有人用ST表做那我就来发一个吧。这道题可以用ST表做。它可以在经过\(O(N\logN)\)的预处理后,以\(O(1)\)的时间在线回答下标在\(l\)到\(r\)之间的数......
  • 【题解】Luogu[P2607] [ZJOI2008] 骑士
    题目说给定\(n\)个点\(n\)个关系,也就是\(n\)条边,显然是基环树,又因为没有规定一定连通,于是我们可以将题目简化为给定一个基环树森林,点有点权,相邻的两个点不能同时选,问最大点权和。part1我们先考虑如果没有环,只是树,该怎么做。这一部分很简单,令\(f_{i,0/1}\)表示以\(i\)......
  • 基站建设 题解
    基站建设题目大意在平面上存在\(n\)个点,第\(i\)个点的坐标为\((x_i,0)\),具有一个发射半径\(r_i\)和一个费用\(v_i\)。连接具有方向性,当且仅当\(j<i\)且点\(i\)的接收范围与点\(j\)的发射范围相切时点\(i\)才能连接到点\(j\)。第\(i\)个点的发射范围是指一......
  • 浅谈关系矩阵
    浅谈关系矩阵什么是关系矩阵关系矩阵就是用矩阵来表示关系,关系矩阵中的数值皆为**0**或**1**(也就是**bool**型)。举个例子:\[\begin{vmatrix}1&0&1\\0&0&1\\1&0&0\end{vmatrix}\]这个关系矩阵就表示了3个抽象物体的关系:\[\begin{vmatrix}1->1......
  • [ARC104E] Random LIS 题解
    [ARC104E]RandomLIS题解Link吐了,一下午就写了这一个题……主要是题解都说的很草率。然后上课的时候貌似讲的方法不是很能做(也许是我太菜了),总之我得写篇题解整理整理。首先\(n\)很小,可以直接爆搜所有相对大小,即我们去搜索\(1\)到\(n\)的排名,排名可以一样(即\(a_i\)相......
  • 线性代数4 初等变换、初等矩阵、分块矩阵、方阵行列式
    1.1初等变换和初等矩阵的概念初等变换的概念:初等变换并不是一个运算操作,而是一类对矩阵的操作的统称对于m×n矩阵A:(1)倍乘:对A的某行或某列元素乘上一个非零常数k(2)互换:互换A的某两列或某两行元素的位置(3)倍加:将A的某行或某列元素的k倍加到另一行或列上这三种变换统称为初等(行......
  • RTSP流媒体服务器LntonNVR(源码版)云服务平台下载录像后无法拖动时间轴的问题解决方案
    LntonNVR安防视频云服务平台是基于RTSP/Onvif协议的视频接入、处理及分发平台,可以分发出RTSP、RTMP、WS-FLV、HTTP-FLV、HLS、WebRTC等格式的视频流,可实现在全终端(PC、手机、平板、电子大屏/电视墙等)播放监控视频。有用户反馈,在使用LntonNVR下载录像时,下载后的录像时间无法拖动时间......
  • 【小学期实训】附加题题解——Good Karma
    [状压dp+容斥原理]实训附加题——GoodKarma目录[状压dp+容斥原理]实训附加题——GoodKarma题目描述题目输入格式输出格式数据范围样例输入1样例输出1样例输入2样例输出2样例解释2Solution题目描述题目链接题目「天空度假山庄」中有一个\(n\)点\(m\)边的无向图,图中点......