【洛谷P7515】矩阵游戏

题目

题目链接:https://www.luogu.com.cn/problem/P7515
Alice 有一个 \(n \times m\) 的矩阵 \(a_{i, j}\)\(1 \le i \le n\)\(1 \le j \le m\)),其每个元素为大小不超过 \({10}^6\) 的非负整数。
Bob 根据该矩阵生成了一个 \((n - 1) \times (m - 1)\) 的矩阵 \(b_{i, j}\)\(1 \le i \le n - 1\)\(1 \le j \le m - 1\)),每个元素的生成公式为

\[b_{i, j} = a_{i, j} + a_{i, j + 1} + a_{i + 1, j} + a_{i + 1, j + 1} \]

现在 Alice 忘记了矩阵 \(a_{i, j}\),请你根据 Bob 给出的矩阵 \(b_{i, j}\) 还原出 \(a_{i, j}\)
\(n,m\leq 300,Q\leq 10\)

思路

首先我们直接随意构造出一组解,然后考虑去修改它使所有数都在 \([0,10^6]\) 内。
我们发现任意一行或一列同时修改,其中第 \(i\) 个数修改 \((-1)^i\times k\),可以似的每一个 \(2\times 2\) 的小正方形的和不变。那我们只需要确定每一行的权值 \(c_i\),每一列的权值 \(d_i\),然后就可以把矩阵修改为

\[\begin{bmatrix} a_{1,1}+c_1+d_1 & a_{1,2}-c_1+d_2 & a_{1,3}+c_1+d_3 & a_{1,4}-c_1+d_4 \\ a_{2,1}+c_2-d_1 & a_{2,2}-c_2-d_2 & a_{2,3}+c_2-d_3 & a_{2,4}-c_2-d_4 \\ a_{3,1}+c_3+d_1 & a_{3,2}-c_3+d_2 & a_{3,3}+c_3+d_3 & a_{3,4}-c_3+d_4 \\ a_{4,1}+c_4-d_1 & a_{4,2}-c_4-d_2 & a_{4,3}+c_4-d_3 & a_{4,4}-c_4-d_4 \end{bmatrix} \]

也就是对于第 \(i\) 行第 \(j\) 列,我们需要满足

\[-a_{i,j}\leq \pm c_i \pm d_j\leq 10^6-a_{i,j} \]

这个东西很像差分约束,但是我们发现矩阵中存在 \(+c_i+d_j\),或 \(-c_i-d_j\) 的部分,我们无法转化为查分约束,所以我们考虑在原矩阵中动手脚。
如果我们把偶数行的 \(c\) 全部取反,奇数行的 \(d\) 全部取反,我们就可以得到

\[\begin{bmatrix} a_{1,1}+c_1-d_1 & a_{1,2}+d_2-c_1 & a_{1,3}+c_1-d_3 & a_{1,4}+d_4-c_1 \\ a_{2,1}+d_1-c_2 & a_{2,2}+c_2-d_2 & a_{2,3}+d_3-c_2 & a_{2,4}+c_2-d_4 \\ a_{3,1}+c_3-d_1 & a_{3,2}+d_2-c_3 & a_{3,3}+c_3-d_3 & a_{3,4}+d_4-c_3 \\ a_{4,1}+d_1-c_4 & a_{4,2}+c_4-d_2 & a_{4,3}+d_3-c_4 & a_{4,4}+c_4-d_4 \end{bmatrix} \]

就可以搞差分约束了。
时间复杂度 \(O(Qnm(n+m))\)。注意不加 SLF 优化会 T 飞。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=310;
int Q,n,m,tot,cnt[N*2],head[N*2];
ll a[N][N],dis[N*2];
bool vis[N*2];

int read()
{
	int d=0; char ch=getchar();
	while (!isdigit(ch)) ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d;
}

struct edge
{
	int next,to,dis;
}e[N*N*2];

void add(int from,int to,int dis)
{
	e[++tot]=(edge){head[from],to,dis};
	head[from]=tot;
}

void prework()
{
	memset(head,-1,sizeof(head));
	memset(a,0,sizeof(a));
	tot=0;
}

bool spfa()
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	memset(cnt,0,sizeof(cnt));
	memset(vis,0,sizeof(vis));
	deque<int> q;
	q.push_back(1); dis[1]=cnt[1]=0;
	while (q.size())
	{
		int u=q.front(); q.pop_front();
		vis[u]=0;
		if (cnt[u]>n+m) return 0;
		for (int i=head[u];~i;i=e[i].next)
		{
			int v=e[i].to;
			if (dis[v]>dis[u]+e[i].dis)
			{
				dis[v]=dis[u]+e[i].dis;
				cnt[v]=cnt[u]+1;
				if (!vis[v])
				{
					vis[v]=1;
					if (dis[v]<dis[q.front()]) q.push_front(v);
						else q.push_back(v);
				}
			}
		}
	}
	return 1;
}

int main()
{
	Q=read();
	while (Q--)
	{
		prework();
		n=read(); m=read();
		for (int i=1;i<n;i++)
			for (int j=1;j<m;j++)
				a[i+1][j+1]=read()-a[i][j]-a[i+1][j]-a[i][j+1];
		for (int i=1;i<=n;i++)
			for (int j=1;j<=m;j++)
				if ((i+j)&1)
					add(j+n,i,a[i][j]),add(i,j+n,1e6-a[i][j]);
				else
					add(i,j+n,a[i][j]),add(j+n,i,1e6-a[i][j]);
		if (!spfa()) { printf("NO\n"); continue; }
		printf("YES\n");
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=m;j++)
				if ((i+j)&1) printf("%d ",(int)(a[i][j]+dis[j+n]-dis[i]));
					else printf("%d ",(int)(a[i][j]+dis[i]-dis[j+n]));
			printf("\n");
		}
	}
	return 0;
}
posted @ 2021-04-24 16:12  stoorz  阅读(59)  评论(0编辑  收藏  举报