[loj3500]矩阵游戏
为了方便,令$a_{i,j}$的下标范围为$[0,n]$和$[0,m]$,$b_{i,j}$的下标范围为$[1,n]$和$[1,m]$
当确定$a_{i,0}$和$a_{0,j}$后,即可通过$b_{i,j}$来确定$a_{i,j}$,具体的有
$$
a_{i,j}=(-1)^{i+j}\sum_{1\le x\le i,1\le y\le j}(-1)^{x+y}b_{x,y}+(-1)^{j}a_{i,0}+(-1)^{i}a_{0,j}-(-1)^{i+j}a_{0,0}
$$
由于在$i=0$或$j=0$时其也满足该式子,因此现在的条件变为:构造任意整数$a_{i,0}$和$a_{0,j}$,使得对于任意$i$和$j$(符合下标范围),上述式子计算得到后的结果在$[0,V]$中(其中$V=10^{6}$)
提出$(-1)^{i+j}$,再令$B_{i,j}=\sum_{1\le x\le i,1\le y\le j}(-1)^{x+y}b_{x,y}$,即有
$$
a_{i,j}=(-1)^{i+j}(B_{i,j}+(-1)^{i}a_{i,0}+(-1)^{j}a_{0,j}-a_{0,0})
$$
令$x_{i}=(-1)^{i}a_{i,0}-a_{0,0}$和$y_{i}=(-1)^{i+1}a_{0,i}$,即$a_{i,j}=(-1)^{i+j}(B_{i,j}+x_{i}-y_{j})$
同时,条件考虑对$i+j$奇偶性分类讨论,即:
1.若$i+j$为偶数,则$-B_{i,j}\le x_{i}-y_{j}\le V-B_{i,j}$
2.若$i+j$为奇数,则$B_{i,j}\le y_{j}-x_{i}\le V+B_{i,j}$
对$x_{i}$和$y_{i}$这$n+m+2$个变量求差分约束即可,具体来说令$d_{i}$表示第$i$个变量的值,限制都可以转换为$d_{i}\le d_{j}+x$,那么连边$(i,j,x)$后求最短路即满足此性质
由于有负权,需要spfa,最坏时间复杂度为$o(T(n+m)^{3})$
求出$x_{i}$和$y_{i}$后,即有$a_{i,j}=(-1)^{i+j}(B_{i,j}+x_{i}-y_{j})$,输出即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 605 4 #define V 1000000 5 #define ll long long 6 struct Edge{ 7 int nex,to; 8 ll len; 9 }edge[N*N]; 10 queue<int>q; 11 int E,t,n,m,head[N],vis[N],sum[N]; 12 ll d[N],b[N][N]; 13 void add(int x,int y,ll z){ 14 edge[E].nex=head[x]; 15 edge[E].to=y; 16 edge[E].len=z; 17 head[x]=E++; 18 } 19 bool spfa(){ 20 memset(d,0x3f,sizeof(d)); 21 memset(vis,0,sizeof(vis)); 22 memset(sum,0,sizeof(sum)); 23 d[0]=0; 24 q.push(0); 25 vis[0]=1; 26 while (!q.empty()){ 27 int k=q.front(); 28 q.pop(); 29 for(int i=head[k];i!=-1;i=edge[i].nex) 30 if (d[edge[i].to]>d[k]+edge[i].len){ 31 d[edge[i].to]=d[k]+edge[i].len; 32 if (!vis[edge[i].to]){ 33 q.push(edge[i].to); 34 vis[edge[i].to]=1; 35 } 36 if (++sum[edge[i].to]>n+m)return 0; 37 } 38 vis[k]=0; 39 } 40 return 1; 41 } 42 int main(){ 43 scanf("%d",&t); 44 while (t--){ 45 scanf("%d%d",&n,&m); 46 n--,m--; 47 E=0; 48 memset(head,-1,sizeof(head)); 49 for(int i=1;i<=n;i++) 50 for(int j=1;j<=m;j++){ 51 scanf("%lld",&b[i][j]); 52 if ((i+j)&1)b[i][j]*=-1; 53 b[i][j]+=b[i-1][j]+b[i][j-1]-b[i-1][j-1]; 54 } 55 for(int i=0;i<=n;i++) 56 for(int j=0;j<=m;j++) 57 if ((i+j)&1){ 58 add(i,j+n+1,V+b[i][j]); 59 add(j+n+1,i,-b[i][j]); 60 } 61 else{ 62 add(j+n+1,i,V-b[i][j]); 63 add(i,j+n+1,b[i][j]); 64 } 65 if (!spfa()){ 66 printf("NO\n"); 67 continue; 68 } 69 printf("YES\n"); 70 for(int i=0;i<=n;i++){ 71 for(int j=0;j<=m;j++) 72 if ((i+j)&1)printf("%lld ",d[j+n+1]-d[i]-b[i][j]); 73 else printf("%lld ",b[i][j]+d[i]-d[j+n+1]); 74 printf("\n"); 75 } 76 } 77 }