「SOL」矩阵游戏 (2021省选A卷)

考前感觉啥都复习了
考后感觉啥啥都不会


# 题面

> Link 洛谷 P7515


# 解析

最难处理的是 \(a_{ij}\) 有 \([0,10^6]\) 的限制(因为有这个限制所以我 \(n,m\le3\) 都不会做……)。

假如没有这个限制,显然我们可以随便构造出一组解 \(\{a'_{ij}\}\),下面给出一种构造方法:

  • 固定最后一行和最后一列都是 \(0\);
  • 从下到上从左到右依次确定 \(a'_{ij}\)(不需要满足范围限制,注意会爆 int

然后考虑如何把 \(\{a'_{ij}\}\) 修修补补使它满足范围限制。

这里的构造非常巧妙,我们可以将第 \(i\) 行的偶数列加上 \(p_i\),奇数列减去 \(p_i\),这样操作后每一个 \(2\times2\) 的矩形的和都不变;将第 \(j\) 列的偶数行加上 \(q_j\),奇数行减去 \(q_j\) 同理。

于是我们要求:

\[\forall i\in[1,n]\land j\in[1,m], 0\le a'_{ij}+(-1)^ip_i+(-1)^jq_j\le 10^6 \]

差不多转化成了下面这种不等式

\[L_{ij}\le p_i\pm q_j\le R_{ij} \]

这个问题似乎也并不好求解,但是我们会用差分约束求解

\[L\le p-q\le R \]

怎么消除掉“两个变量之和”的不等式?考虑改变我们的构造方式,原本我们构造的方式是

\[\begin{bmatrix} -p_1&+p_1&-p_1&\cdots\\ -p_2&+p_2&-p_2&\cdots\\ -p_3&+p_3&-p_3&\cdots\\ \vdots&\vdots&\vdots&\ddots \end{bmatrix}+\begin{bmatrix} -q_1&-q_2&-q_3&\cdots\\ +q_1&+q_2&+q_3&\cdots\\ -q_1&-q_2&-q_3&\cdots\\ \vdots&\vdots&\vdots&\ddots \end{bmatrix} \]

我们发现,在 \(i,j\) 奇偶性相同的位置,会出现变量之和的限制,于是我们稍作调整:

\[\begin{bmatrix} -p_1&+p_1&-p_1&\cdots\\ +p_2&-p_2&+p_2&\cdots\\ -p_3&+p_3&-p_3&\cdots\\ \vdots&\vdots&\vdots&\ddots \end{bmatrix}+\begin{bmatrix} +q_1&-q_2&+q_3&\cdots\\ -q_1&+q_2&-q_3&\cdots\\ +q_1&-q_2&+q_3&\cdots\\ \vdots&\vdots&\vdots&\ddots \end{bmatrix} \]

不难发现,这样构造仍然可以让 \(2\times2\) 的矩形和不变。而这样构造的好处就在于,对应位置的正负性总相反。

然后就可以非常愉快地差分约束。

如果有负环就无解。有负权边,跑 SPFA?反正我会被卡常,看题解发现可以直接 bellman-ford,而且因为是完全二分图,可以用邻接矩阵存边。

跑得特别慢……

最后还有一点小问题。为什么这样是对的呢?我们感觉这个算法看起来就非常对…… 给出一个不是很严谨的证明。

证明

起初对这道题有一个非常暴力的想法:如果确定了 \(\{a_{ij}\}\) 的最后一行和最后一列,那么可以唯一确定矩阵 \(\{a_{ij}\}\)(在忽略范围限制的前提下)。也就是说,我们可以用最后一行、最后一列代表一个矩阵。

假设存在合法解 \(\{a_{ij}\}\),那么通过 \(a_{im}\pm p_i\) 和 \(a_{nj}\pm q_j\),可以得到任意一种 \(a'_{im},a'_{nj}\),也即可以得到任意一种不符合范围限制的矩阵 \(\{a'_{ij}\}\)。

为什么会存在多解呢?因为实际上最后一行和最后一列只能提供 \(n+m-1\) 个方程,而我们有 \(n+m\) 个变量。


# 源代码

/*Lucky_Glass*/
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long llong;
const int N = 305, M = N * N, B = 1e6;
const llong INF = 0x3f3f3f3f3f3f3f3fll;
#define con(typ) const typ &
inline int rin(int &r) {
	int b = 1, c = getchar(); r = 0;
	while ( c < '0' || '9' < c ) b = c == '-' ? -1 : b, c = getchar();
	while ( '0' <= c && c <= '9' ) r = (r * 10) + (c ^ '0'), c = getchar();
	return r *= b;
}
void write(con(int) w) {
	if ( w < 0 ) putchar('-'), write(-w);
	else if ( w < 10 ) putchar('0' + w);
	else write(w / 10), putchar('0' + w % 10);
}

int n, m, nedg;
int mtb[N][N];
llong mta[N][N], edga[N][N], edgb[N][N];
llong dis[N << 1];

bool relax(con(int) u, con(llong) len, con(int) v) {
	if ( dis[v] > dis[u] + len ) {
		dis[v] = dis[u] + len;
		return true;
	}
	return false;
}
bool bellmanFord() {
	int cnt = 0; bool tag = false;
	for (int i = 1; i <= n + m; i++)
		dis[i] = 0;
	do {
		cnt++, tag = false;
		if ( cnt >= n + m ) return false;
		for (int u = 1; u <= n + m; u++)
			if ( u <= n )
				for (int v = 1; v <= m; v++)
					tag |= relax(u, edga[u][v], v + n);
			else
				for (int v = 1; v <= n; v++)
					tag |= relax(u, edgb[u - n][v], v);
	} while ( tag );
	return true;
}
void clean() {
	nedg = 0;
	fill(dis, dis + n + m + 1, INF);
}
int main() {
	int ncas; rin(ncas);
	while ( ncas-- ) {
		rin(n), rin(m);
		clean();
		for (int i = 1; i < n; i++)
			for (int j = 1; j < m; j++)
				rin(mtb[i][j]);
		for (int i = n; i; i--)
			for (int j = m; j; j--)
				if ( i == n || j == m ) mta[i][j] = 0;
				else mta[i][j] = mtb[i][j] - mta[i + 1][j + 1]
							   - mta[i + 1][j] - mta[i][j + 1];
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++)
				if ( (i & 1) ^ (j & 1) )
					edga[i][j] = mta[i][j], edgb[j][i] = B - mta[i][j];
				else
					edgb[j][i] = mta[i][j], edga[i][j] = B - mta[i][j];
		if ( !bellmanFord() ) {printf("NO\n"); continue;}
		printf("YES\n");
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= m; j++) {
				llong now = mta[i][j];
				if ( (i & 1) ^ (j & 1) ) now += dis[i] - dis[j + n];
				else now += dis[j + n] - dis[i];
				write((int)now), putchar(j == m ? '\n' : ' ');
			}
	}
	return 0;
}

THE END

Thanks for reading!

你走吧 趁着天色未暗
你走吧 深知道阻且难
我献上明月一盏 照满河山

——《山遥路远(人声本家)》By ChiliChill

PS. 省选之后再听这首歌又有不一样的感动,似乎是我将此歌唱给谁人,又像是谁人唱予我。

上一篇:收获,不止SOL优化抓住SQL的本质


下一篇:计算几何基础