题目描述:
$T$组询问,每次给出$m,n,q$以及$q$组限制,求一个$m*n$的矩阵,满足:
- 每一行/列之和等于给出的每一行/列之和。
- 对于每组限制$(x,y,op,w)$(若$x$或$y$为$0$则代表一整行/列),满足所有限制中的元素都大于/等于/小于$w$。
题解:
有源汇有上下界可行流板子题+墙题。
每一行/列都看作一个点$x$。矩阵里的数就是相连的边权。
对于限制$1$,可以看作$S$连$x$/$x$连$T$的边上下界都为给出值$k$;
对于限制$2$,可以看作$x$与$y$相连的边上下界修改。
最后按有源汇可行流套路建图即可。
注意$x$可能连$y$,也可能连旧源汇和新源汇……
代码:
#include<queue> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 350; const int inf = 0x3f3f3f3f; const ll Inf = 0x3f3f3f3f3f3f3f3fll; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } int _,m,n,Q,S,T,SS,TT,hed[N],cnt=1; ll v1[N][2],v2[N][2],v3[N][N][2],v4[2],s[2][N],fin[N],fout[N]; void chkmax(ll&x,ll y){if(x<y)x=y;} void chkmin(ll&x,ll y){if(x>y)x=y;} char op[10]; void orz(){puts("IMPOSSIBLE");} void clear() { memset(hed,0,sizeof(hed)); memset(fin,0,sizeof(fin)); memset(fout,0,sizeof(fout)); for(int i=1;i<=m;i++) v1[i][0]=0,v1[i][1]=Inf; for(int i=1;i<=n;i++) v2[i][0]=0,v2[i][1]=Inf; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) v3[i][j][0]=0,v3[i][j][1]=Inf; v4[0] = 0,v4[1] = Inf; cnt = 1; S = n+m+1,T = S+1,SS = T+1,TT = SS+1; } struct EG { int to,nxt; ll fl; }e[60*N]; void ae(int f,int t,ll fl) { e[++cnt].to = t; e[cnt].nxt = hed[f]; e[cnt].fl = fl; hed[f] = cnt; } void AE(int f,int t,ll fl) { ae(f,t,fl); ae(t,f,0); } int cur[N],dep[N]; bool vis[N]; bool bfs() { queue<int>q; memcpy(cur,hed,sizeof(cur)); memset(dep,0x3f,sizeof(dep)); dep[SS] = 0,vis[SS] = 1;q.push(SS); while(!q.empty()) { int u = q.front(); q.pop(); for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(e[j].fl&&dep[to]>dep[u]+1) { dep[to] = dep[u]+1; if(!vis[to])vis[to]=1,q.push(to); } } vis[u] = 0; } return dep[TT]!=inf; } ll dfs(int u,ll lim) { if(u==TT||!lim)return lim; ll fl = 0,f; for(int j=cur[u];j;j=e[j].nxt) { cur[u] = j; int to = e[j].to; if(dep[to]==dep[u]+1&&(f=dfs(to,min(lim,e[j].fl)))) { fl+=f,lim-=f; e[j].fl-=f,e[j^1].fl+=f; if(!lim)break; } } return fl; } ll dinic() { ll ret = 0; while(bfs())ret+=dfs(SS,Inf); return ret; } int main() { // freopen("tt.in","r",stdin); read(_); while(_--) { read(m),read(n); clear(); for(int i=1;i<=m;i++) read(s[0][i]); for(int i=1;i<=n;i++) read(s[1][i]); read(Q); ll w; for(int x,y,i=1;i<=Q;i++) { read(x),read(y); scanf("%s",op+1); read(w); if(op[1]=='=') { if(x&&y)chkmax(v3[x][y][0],w),chkmin(v3[x][y][1],w); else if(!x&&y)chkmax(v2[y][0],w),chkmin(v2[y][1],w); else if(x&&!y)chkmax(v1[x][0],w),chkmin(v1[x][1],w); else chkmax(v4[0],w),chkmin(v4[1],w); }else if(op[1]=='<') { w--; if(x&&y)chkmin(v3[x][y][1],w); else if(!x&&y)chkmin(v2[y][1],w); else if(x&&!y)chkmin(v1[x][1],w); else chkmin(v4[1],w); }else { w++; if(x&&y)chkmax(v3[x][y][0],w); else if(!x&&y)chkmax(v2[y][0],w); else if(x&&!y)chkmax(v1[x][0],w); else chkmax(v4[0],w); } } bool ORZ = 0; if(v4[0]>v4[1])ORZ=1; for(int i=1;!ORZ&&i<=m;i++) { chkmax(v1[i][0],v4[0]); chkmin(v1[i][1],v4[1]); if(v1[i][0]>v1[i][1])ORZ=1; } for(int i=1;!ORZ&&i<=n;i++) { chkmax(v2[i][0],v4[0]); chkmin(v2[i][1],v4[1]); if(v2[i][0]>v2[i][1])ORZ=1; } for(int i=1;!ORZ&&i<=m;i++) for(int j=1;!ORZ&&j<=n;j++) { chkmax(v3[i][j][0],max(v1[i][0],v2[j][0])); chkmin(v3[i][j][1],min(v1[i][1],v2[j][1])); if(v3[i][j][0]>v3[i][j][1])ORZ=1; } if(ORZ){orz();continue;} ll sum = 0; for(int i=1;i<=m;i++) AE(S,i,0),fin[i]+=s[0][i],fout[S]+=s[0][i]; for(int i=1;i<=n;i++) AE(i+m,T,0),fin[T]+=s[1][i],fout[i+m]+=s[1][i]; for(int i=1;i<=m;i++) for(int j=n;j>=1;j--) AE(i,j+m,v3[i][j][1]-v3[i][j][0]),fin[j+m]+=v3[i][j][0],fout[i]+=v3[i][j][0]; AE(T,S,Inf); for(int i=1;i<=T;i++) if(fin[i]>fout[i])AE(SS,i,fin[i]-fout[i]),sum+=fin[i]-fout[i]; else AE(i,TT,fout[i]-fin[i]); if(sum!=dinic()){orz();continue;} else { for(int i=1;i<=m;puts(""),i++) for(int j=hed[i],to;j;j=e[j].nxt)if((to=e[j].to)!=SS&&to!=S&&to!=TT) printf("%lld ",v3[i][to-m][1]-e[j].fl); puts(""); } } return 0; }