『省选联考 2021 A 卷』矩阵游戏的题解
题意
有一个
问你是否存在
题解
首先,可以很容易地构造出一个只满足
所以,我们根据每个
然而这并不仅有我们熟知的 差分约束 ,还有 “和分约束”,怎么办呢?
之所以会出现和,是因为有些地方行列的符号相同。解决方案就是:
类似两种不同的黑白格染色,就使得每个位置的符号都不相同了,也就转化成了差分约束。
实现细节
由于我们建的图是一张完全图,边数多,
一个问题
还有一个疑问,也是大部分题解中没有说明的一点,就是:
是否只要有这两个操作就可以让矩阵
证明如下:
引理:如果一个
我们的两种修改操作由于每次修改一行或一列,如果先改第一行再改第一列,就显然可以把
代码
#define ll long long
const ll inf = 1e18;
const int N = 305, MX = 1000000;
int n,m;
ll a[N][N],b[N][N];
int id(int x,int y) { return (x-1)*n+y; }
namespace diff {
struct edge {int to,w; };
ll c[N*2],g[N*2][N*2];
void init() {
for(int i = 0; i <= n+m; ++i) {
for(int j = 0; j <= n+m; ++j) {
diff::g[i][j] = inf;
}
}
}
void adde(int u,int v,int w) { g[u][v] = w; }
bool run() {
memset(c,0x3f,sizeof(c));
c[0] = 0;
for(int i = 1; i <= n+m; ++i) g[0][i] = 0;
int ti,l,r;
for(ti = 1; ti <= n+m+1; ++ti) {
int rel = 0;
for(int u = 0; u <= n+m; ++u) {
if(u == 0) l = 1, r = n+m;
else if(u <= n) l = n+1, r = n+m;
else l = 1, r = n;
for(int v = l; v<= r; ++v) {
rel |= umin(c[v], c[u]+g[u][v]);
}
}
if(!rel) break;
}
return ti < n+m+1;
}
void output() {
puts("YES");
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
if((i+j)&1) a[i][j] = a[i][j] + c[i] - c[n+j];
else a[i][j] = a[i][j] - c[i] + c[n+j];
printf("%lld ",a[i][j]);
}
puts("");
}
}
}
signed main()
{
int T; read(T);
for(int cs = 1; cs <= T; ++cs) {
read(n); read(m);
diff::init();
for(int i = 1; i < n; ++i) for(int j = 1; j < m; ++j) read(b[i][j]);
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) a[i][j] = 0;
}
for(int i = 2; i <= n; ++i) {
for(int j = 2; j<= m; ++j) {
a[i][j] = b[i-1][j-1] - a[i-1][j] - a[i][j-1] - a[i-1][j-1];
}
}
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
if((i+j)&1) {
diff::adde(i,j+n,a[i][j]);
diff::adde(j+n,i,MX-a[i][j]);
}
else {
diff::adde(i,j+n,MX-a[i][j]);
diff::adde(j+n,i,a[i][j]);
}
}
}
if(!diff::run()) puts("NO");
else diff::output();
}
return 0;
}