docker 安裝tomcat
阿新 • • 發佈:2021-10-14
構造題其實可以調整做。
\[\begin{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}
\] ,再轉換一下變成 \(-a_{i,j}\le \Delta_{i,j}\le 10^6-a_{i,j}\),連邊即可。
前言
緩慢填坑ing
差分約束的題還是見少了,完全沒思路。
Acetyl orz
題目
講解
首先我們不考慮 \(10^6\) 這個限制,顯然做法很多,比如強制 \(a_{n,i}=a_{j,m}=0\),然後遞推一下就好了。
然後調整解決問題。
可以發現一行如果 \(+r\ -r\ +r\ -r,...\),並不會對 \(b\) 矩陣產生影響,同理,一列也沒有影響,於是我們可以構造出這麼一個矩陣表示調整值:
\[\begin{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} \]但這個矩陣的形式並不好看,我們微調一下:
這樣看上去就統一多了,然後直接套差分約束即可。
具體的,上述矩陣為 \(\Delta_{i,j}=X-Y\) 的形式,可以得到不等式 \(0\le a_{i,j}+\Delta_{i,j}\le 10^6\)
值得注意的是如果使用裸的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\n");continue;} printf("YES\n"); for(int i = 1;i <= n;++ i,putchar('\n')) 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; }