マトリックス
所与\(N \回\ M)行列整数\(A \) 、あなたが構築する必要が\(N \回\ m)の整数の行列\(B \) 、満足\(B \)それぞれを要素\(B_ {i、j} \ in [L、R] \)。
定義\(r(i)= | \ sum_ {j = 1} ^ {m} A_ {i、j}-\ sum_ {j = 1} ^ m B_ {i、j} | \)、つまり2つの行列行\(i \)の要素の合計の差。
定義\(C(J)= | \ sum_ = {I} 1 A_ ^ {N-I、J} - \ sum_ 1} = {J ^ B_ {M I、J} | \)、即ち2マトリックス\ (j \)列要素の合計の差。
\(\ max \ lbrace \ max_ {i = 1} ^ nr(i)、\ max_ {j = 1} ^ mc(j)\ rbrace \)の最小値を要求し、一連の構築行列\(B \)このスキームでは、この最小値が取得されます。
複数の法的構築スキームがある場合は、そのうちの1つだけを出力する必要があります。
\(n、m \ le 200、0 \ le L \ le R \ le 1000、0 \ le A_ {i、j} \ le 1000 \)。
解決策
2つの行列を重ね合わせると、各グリッドの要素\((i、j)\)は\(A_ {i、j)-R + x〜(x \ in [0、RL])\と見なすことができます)。
考えてもよい(R(I)は、C \ (j)が\) 、初期値を持っている\(X \)調整として\(R(I)\)と\(C(J)\)変数。
のでハーフ答え、\(RL \)非負、および\(R(I)、C (J)\) に必要な量を調整するためには、非負の範囲に属している必要があり、そうであってもサイドのランクは、後に上下に翻訳します境界流。
CO int N=410,inf=1e9;
namespace flow{
int S,T;
struct edge {int y,c,a;};
vector<edge> to[N];
int dis[N];
IN void init(int n){
S=n-1,T=n;
for(int i=1;i<=T;++i) to[i].clear();
}
IN void link(int x,int y,int c){
to[x].push_back((edge){y,c}),to[y].push_back((edge){x,0});
to[x].back().a=to[y].size()-1,to[y].back().a=to[x].size()-1;
}
bool bfs(){
fill(dis+1,dis+T+1,inf),dis[T]=0;
deque<int> Q(1,T);
while(Q.size()){
int x=Q.front();Q.pop_front();
for(int i=0;i<(int)to[x].size();++i){
CO edge&e=to[x][i];
if(to[e.y][e.a].c and dis[e.y]>dis[x]+1)
dis[e.y]=dis[x]+1,Q.push_back(e.y);
}
}
return dis[S]<inf;
}
int dfs(int x,int lim){
if(x==T) return lim;
int rest=lim;
for(int i=0;i<(int)to[x].size();++i){
edge&e=to[x][i];
if(e.c and dis[e.y]==dis[x]-1){
int delta=dfs(e.y,min(e.c,rest));
if(!delta) {dis[e.y]=inf; continue;}
rest-=delta,e.c-=delta,to[e.y][e.a].c+=delta;
if(!rest) break;
}
}
return lim-rest;
}
int main(){
int ans=0;
while(bfs()) ans+=dfs(S,inf);
return ans;
}
}
int n,m,A[N][N],B[N][N];
int L,R,row[N],col[N];
int in[N],out[N];
bool solve(int lim){
flow::init(n+m+4);
int s=n+m+1,t=n+m+2;
flow::link(t,s,inf);
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) flow::link(i,n+j,R-L);
fill(in+1,in+t+1,0),fill(out+1,out+t+1,0);
for(int i=1;i<=n;++i){
if(row[i]>=-lim) {flow::link(s,i,lim-row[i]); continue;}
out[s]+=-lim-row[i],in[i]+=-lim-row[i];
flow::link(s,i,2*lim);
}
for(int j=1;j<=m;++j){
if(col[j]>=-lim) {flow::link(n+j,t,lim-col[j]); continue;}
out[n+j]+=-lim-col[j],in[t]+=-lim-col[j];
flow::link(n+j,t,2*lim);
}
for(int i=1;i<=t;++i){
if(in[i]>out[i]) flow::link(flow::S,i,in[i]-out[i]);
else if(in[i]<out[i]) flow::link(i,flow::T,out[i]-in[i]);
}
flow::main();
for(int i=0;i<(int)flow::to[flow::S].size();++i){
CO flow::edge&e=flow::to[flow::S][i];
if(e.c>0) return 0;
}
for(int i=0;i<(int)flow::to[flow::T].size();++i){
CO flow::edge&e=flow::to[flow::T][i];
if(flow::to[e.y][e.a].c>0) return 0;
}
return 1;
}
int main(){
// freopen("mat.in","r",stdin),freopen("mat.out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) read(A[i][j]);
read(L),read(R);
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) A[i][j]-=R;
int l=0,r=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j) row[i]+=A[i][j];
if(row[i]>0) l=max(l,row[i]);
r=max(r,abs(row[i]));
}
for(int j=1;j<=m;++j){
for(int i=1;i<=n;++i) col[j]+=A[i][j];
if(col[j]>0) l=max(l,col[j]);
r=max(r,abs(col[j]));
}
while(l<r){
int mid=(l+r)>>1;
if(solve(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",l);
solve(l);
for(int i=1;i<=n;++i){
for(int j=0;j<(int)flow::to[i].size();++j){
CO flow::edge&e=flow::to[i][j];
if(n+1<=e.y and e.y<=n+m) B[i][e.y-n]=R-(R-L-e.c);
}
}
for(int i=1;i<=n;++i)for(int j=1;j<=m;++j) printf("%d%c",B[i][j]," \n"[j==m]);
return 0;
}