前言
缓慢填坑ing
差分约束的题还是见少了,完全没思路。
Acetyl orz
题目
讲解
首先我们不考虑 (10^6) 这个限制,显然做法很多,比如强制 (a_{n,i}=a_{j,m}=0),然后递推一下就好了。
然后调整解决问题。
可以发现一行如果 (+r -r +r -r,...),并不会对 (b) 矩阵产生影响,同理,一列也没有影响,于是我们可以构造出这么一个矩阵表示调整值:
[egin{pmatrix}&r_1+c_1 &-r_1+c_2 &r_1+c_3,&cdots\&r_2-c_1 &-r_2-c_2 &r_2-c_3,&cdots\&r_3+c_1 &-r_3+c_2 &r_3+c_3,&cdots\&vdots&vdots&vdots&ddots\end{pmatrix}
]
但这个矩阵的形式并不好看,我们微调一下:
[egin{pmatrix}&r_1-c_1 &c_2-r_1 &r_1-c_3,&cdots\&c_1-r_2 &r_2-c_2 &c_3-r_2,&cdots\&r_3-c_1 &c_2-r_3 &r_3-c_3,&cdots\&vdots&vdots&vdots&ddots\end{pmatrix}
]
这样看上去就统一多了,然后直接套差分约束即可。
具体的,上述矩阵为 (Delta_{i,j}=X-Y) 的形式,可以得到不等式 (0le a_{i,j}+Delta_{i,j}le 10^6),再转换一下变成 (-a_{i,j}le Delta_{i,j}le 10^6-a_{i,j}),连边即可。
值得注意的是如果使用裸的SPFA判负环会TLE,你可使用上文提到的巨佬的deque
优化写法,也可以使用洛谷上评测更快的stack
写法。个人经验是如果用SPFA判负环,stack
会快很多。
虽然感觉时间复杂度很离谱,但是可以通过。
代码
代码不长,容易理解
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std;
typedef long long LL;
const int MAXN = 305;
const LL INF = 1ll << 60;
int n,m;
int a[MAXN][MAXN],b[MAXN][MAXN];
bool inq[MAXN<<1];
LL dis[MAXN<<1];
LL Read()
{
LL x = 0,f = 1; char c = getchar();
while(c > '9' || c < '0'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
TT void Put1(T x)
{
if(x > 9) Put1(x/10);
putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
if(x < 0) putchar('-'),x = -x;
Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}
int head[MAXN<<1],tot,cnt[MAXN<<1];
struct edge
{
int v,w,nxt;
}e[MAXN*MAXN*4];
void Add_Edge(int x,int y,int z)
{
e[++tot] = edge{y,z,head[x]};
head[x] = tot;
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
for(int T = Read(); T ;-- T)
{
n = Read(); m = Read();
for(int i = 1;i < n;++ i)
for(int j = 1;j < m;++ j)
b[i][j] = Read();
for(int i = 1;i <= m;++ i) a[n][i] = 0;
for(int i = 1;i <= n;++ i) a[i][m] = 0;
for(int i = n-1;i >= 1;-- i)
for(int j = m-1;j >= 1;-- j)
a[i][j] = b[i][j] - a[i+1][j] - a[i][j+1] - a[i+1][j+1];
for(int i = 1;i <= n+m;++ i) head[i] = cnt[i] = 0,inq[i] = 0,dis[i] = INF; tot = 0;
for(int i = 1;i <= n;++ i)
for(int j = 1;j <= m;++ j)
{
int MIN = -a[i][j],MAX = 1000000-a[i][j];
if((i+j)&1) //c-r
{
Add_Edge(n+j,i,-MIN);
Add_Edge(i,n+j,MAX);
}
else //r-c
{
Add_Edge(i,n+j,-MIN);
Add_Edge(n+j,i,MAX);
}
}
stack<int> q; q.push(1); dis[1] = 0;
bool nonono = 0;
while(!q.empty())
{
int x = q.top(); q.pop(); inq[x] = 0;
for(int i = head[x],v; i && !nonono ;i = e[i].nxt)
{
v = e[i].v;
if(dis[x]+e[i].w < dis[v])
{
dis[v] = dis[x] + e[i].w;
if(!inq[v])
{
q.push(v);
++cnt[v];
if(cnt[v] > n+m) nonono = 1;
inq[v] = 1;
}
}
}
}
if(nonono) {printf("NO
");continue;}
printf("YES
");
for(int i = 1;i <= n;++ i,putchar('
'))
for(int j = 1;j <= m;++ j)
{
if((i+j)&1) //c-r
Put(a[i][j]+dis[n+j]-dis[i],' ');
else
Put(a[i][j]+dis[i]-dis[n+j],' ');
}
}
return 0;
}