P7515 [省选联考 2021 A 卷] 矩阵游戏

· · 题解

题目传送门

题目大意

有一个 n \times m 的矩阵 A,你用其生成了一个 (n-1) \times (m-1) 的矩阵 B,满足 b_{i, j}=a_{i,j}+a_{i,j+1}+a_{i+1,j}+a_{i+1,j+1}

现给出矩阵 B,要求得到原来的矩阵 A,元素值域 [0,\ 10^6]

丢掉限制,那么这道就是个弱智题。

因为

b_{i, j}=a_{i, j}+a_{i,j+1}+a_{i+1,j}+a_{i+1,j+1} a_{i, j}=b_{i, j}-a_{i,j+1}-a_{i+1,j}-a_{i+1,j+1}

所以我们选择从矩阵右下角逆推,这样在求 a_{i, j} 的时候,剩下四个元素就全部是已知的了。

但是我们还得考虑值域的影响。

思考什么样的操作不会影响到 B 矩阵。

由于 B 矩阵的生成相当于一个 4 \times 4 的矩阵:

a_{i, j} & a_{i, j+1}\\ a_{i+1, j} & a_{i+1, j+1} \end{bmatrix}$ 的和,所以,我们可以在每一个元素上面 $\pm$ 一个值 $r$,同时为了保证 $b_{i, j}$ 不变化,所以必然是 $+ 2 \times r$ 和 $- 2 \times r$, 那么操作后的矩阵是这个亚子的: $$\begin{bmatrix} a_{i, j}+r & a_{i, j+1}-r\\ a_{i+1, j}-r & a_{i+1, j+1}+r \end{bmatrix}$$ 又由于我们需要维护整个 $B$,所以我们拓展到整个矩阵: $$\begin{bmatrix} a_{1, 1}+r & a_{1, 2}-r & ... & a_{1, n-1}+r \times (-1)^{n-2} & a_{1, n}+r \times (-1)^{n-1}\\ a_{2, 1}+r & a_{2, 2}-r & ... & a_{2, n-1}+r \times (-1)^{n-2} & a_{2, n}+r \times (-1)^{n-1}\\ ... & ... & ... & ... & ...\\ a_{n-1, 1}+r & a_{n-1, 2}-r & ... & a_{n-1, n-1}+r \times (-1)^{n-2} & a_{n-1, n}+r \times (-1)^{n-1}\\ a_{n, 1}+r & a_{n, 2}-r & ... & a_{n, n-1}+r \times (-1)^{n-2} & a_{n, n}+r \times (-1)^{n-1} \end{bmatrix}$$ 这时候就可以猜个性质:对某一行交替 $+r,-r,+r,-r$ 后对 $B$ 没有影响。 同理列也一致。 证明的话,对于任意的 $b_{i, j}$ 由于加减是交替的,所以 $new\ b_{i, j}=b_{i, j} +r -r =b_{i, j}$,回到了最初的值。 那我们就设第 $i$ 行的 $r$ 是 $dis_i$ ,第 $j$ 列的 $r$ 是 $dis_{n+j}$,由于这样的话某几行/列就是 $a_{i, j}+dis_i+dis_{n+j}$,那么我们重设 $dis_i=(-1)^i \times dis_i, dis_{j+n}=(-1)^{j+1} \times dis_{j+n}$ 后,矩阵不管那一行/列,就都能满足差分约束的板子了。 ### Code ``` #include <stdio.h> #include <algorithm> #include <string.h> #include <queue> #include <vector> using namespace std; typedef long long ll; const int N=305; const int L=0; const int R=1e6; const int INF=0x3f3f3f3f; inline int read(){ char ch=getchar();int x=0, f=1; while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();} return x*f; } int n, m, a[N][N], b[N][N]; ll dis[N<<1]; vector < pair <int, int> > G[N<<1]; struct StPh{ int cnt[N<<1]; bool in[N<<1]; queue <int> Q; void clear(){ memset(cnt, 0, sizeof(cnt)); memset(in, 0, sizeof(in)); while(!Q.empty()) Q.pop(); } bool spfa(){ dis[1]=0, Q.push(1); while(!Q.empty()){ int x=Q.front();Q.pop();in[x]=0, cnt[x]++; if(cnt[x]>n+m) return 1; int sz=(int)G[x].size(); for(int i=0; i<sz; i++){ int to=G[x][i].first, w=G[x][i].second; if(dis[to]>dis[x]+w){ dis[to]=dis[x]+w; if(!in[to]) Q.push(to), in[to]=1; } } } return 0; } }stph; void clear(){ memset(a, 0, sizeof(a)); memset(dis, 9, sizeof(dis)); for(int i=1; i<=n+m; i++) G[i].clear(); stph.clear(); } int solve(){ n=read(), m=read(); clear(); for(int i=1; i<n; i++) for(int j=1; j<m; j++) b[i][j]=read(); for(int i=n; i; i--) for(int j=m; j; j--) a[i][j]=b[i][j]-a[i+1][j]-a[i+1][j+1]-a[i][j+1]; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++){ if((i+j)&1) G[j+n].push_back(make_pair(i, a[i][j])), G[i].push_back(make_pair(j+n, 1e6-a[i][j])); else G[j+n].push_back(make_pair(i, 1e6-a[i][j])), G[i].push_back(make_pair(j+n, a[i][j])); } if(stph.spfa()) return 0*printf("NO\n"); printf("YES\n"); for(int i=1; i<=n; i++, puts("")) for(int j=1; j<=m; j++){ a[i][j]+=(((i+j)&1)?-1:1)*dis[i]; a[i][j]+=(((i+j)&1)?1:-1)*dis[j+n]; printf("%d ", a[i][j]); } return 0; } signed main(){ int T=read(); for(; T; T--) solve(); return 0; } ```