大量证明缺失,只有构造方法。参考 std。
思路
令 ,。当 时认为 的符号是正确的。记 为一个不全相同的行, 为一个不全相同的列。
如果能构造出合法的 ,可以同 arc135d 的方法,取出同符号的 消掉绝对值较小的,再取出符号相反的 或 消掉绝对值较小的。
如果存在 。找到一个 ,枚举 和 的符号,令 ,带进去解 ,有唯一解。然后调整,令 初始为 使 。
如果不存在 和 ,即所有 相等。如果 为偶数,构造 ,前 个 为 ,其他为 。否则 为奇数,令 全为 ,有 个 为 , 个为 ,有 。,枚举 求 。 为奇偶也同理。
否则 只有一个有值,反转 使 有值。因为每列的 都相等,构造第一行复制 次。所以有 ,,。所以 。设 表示前 个 的和为 是否可行。当 时要求 , dp 取模后的 。 时要求,bitset 加速。
code
int n,m;
int a[maxn][maxn],c[maxn][maxn],b[maxn][maxn];
int f[maxn],g[maxn];
void get(){
vector<int> f1,f2,g1,g2;
for(int i=1;i<=n;i++){
if(f[i]<0)f1.pb(i);
if(f[i]>0)f2.pb(i);
}
for(int j=1;j<=m;j++){
if(g[j]<0)g1.pb(j);
if(g[j]>0)g2.pb(j);
}
while(f1.size()&&g1.size()){
int u=f1.back(),v=g1.back();f1.pop_back(),g1.pop_back();
int d=min(abs(f[u]),abs(g[v]));
a[u][v]-=d;f[u]+=d,g[v]+=d;
if(f[u])f1.pb(u);
if(g[v])g1.pb(v);
}
while(f2.size()&&g2.size()){
int u=f2.back(),v=g2.back();f2.pop_back(),g2.pop_back();
int d=min(abs(f[u]),abs(g[v]));
a[u][v]+=d;f[u]-=d,g[v]-=d;
if(f[u])f2.pb(u);
if(g[v])g2.pb(v);
}
while(f1.size()&&f2.size()){
int u=f1.back(),v=f2.back();f1.pop_back(),f2.pop_back();
int d=min(abs(f[u]),abs(f[v]));
a[u][1]-=d,a[v][1]+=d;f[u]+=d,f[v]-=d;
if(f[u])f1.pb(u);
if(f[v])f2.pb(v);
}
while(g1.size()&&g2.size()){
int u=g1.back(),v=g2.back();g1.pop_back(),g2.pop_back();
int d=min(abs(g[u]),abs(g[v]));a[1][u]-=d,a[1][v]+=d;
g[u]+=d,g[v]-=d;
if(g[u])g1.pb(u);
if(g[v])g2.pb(v);
}
}
void check(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)printf("%lld ",a[i][j]);puts("");
}
for(int i=1;i<=n;i++)f[i]=0;
for(int j=1;j<=m;j++)g[j]=0;
for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)f[i]+=a[i][j],g[j]+=a[i][j];
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)if(b[i][j]!=abs(g[j]-f[i]))assert(0);
}
}
int p1,p2,p3;
bool work_dif(int v1,int v2){
f[p1]=0,g[p2]=v1,g[p3]=v2;
for(int i=1;i<=n;i++)if(i!=p1){
if(abs(v1+c[i][p2]-v2)==c[i][p3]){f[i]=v1+c[i][p2];continue;}
if(abs(v1-c[i][p2]-v2)==c[i][p3]){f[i]=v1-c[i][p2];continue;}
return 0;
}
for(int j=1;j<=m;j++)if(j!=p2&&j!=p3){
int v=f[1]+c[1][j],fl=1;
for(int i=1;i<=n;i++)fl&=abs(v-f[i])==c[i][j];
if(fl){g[j]=v;continue;}
v=f[1]-c[1][j],fl=1;
for(int i=1;i<=n;i++)fl&=abs(v-f[i])==c[i][j];
if(fl){g[j]=v;continue;}
return 0;
}
int sum=0;
for(int i=1;i<=n;i++)sum+=f[i];
for(int j=1;j<=m;j++)sum-=g[j];
if(n==m)return !sum;
if(abs(sum)%abs(n-m))return 0;
int d=sum/(n-m);
for(int i=1;i<=n;i++)f[i]-=d;
for(int j=1;j<=m;j++)g[j]-=d;
return 1;
}
void work_sam(){
if(!c[1][1])return ;
if(!(n&1)){
for(int i=1;i<=n/2;i++)f[i]=c[1][1];
for(int i=n/2+1;i<=n;i++)f[i]=-c[1][1];
return ;
}
if(!(m&1)){
for(int i=1;i<=m/2;i++)g[i]=c[1][1];
for(int i=m/2+1;i<=m;i++)g[i]=-c[1][1];
return ;
}
for(int n1=0;n1<=n;n1++){
int n2=n-n1,d=n1-n2;
if(abs(c[1][1]*d)%abs(m-n)==0){
int x=c[1][1]*d/(m-n);
for(int i=1;i<=n1;i++)f[i]=x+c[1][1];
for(int i=n1+1;i<=n;i++)f[i]=x-c[1][1];
for(int j=1;j<=m;j++)g[j]=x;
return ;
}
}
for(int m1=0;m1<=m;m1++){
int m2=m-m1,d=m1-m2;
if(abs(c[1][1]*d)%abs(n-m)==0){
int x=c[1][1]*d/(n-m);
for(int j=1;j<=m1;j++)g[j]=x+c[1][1];
for(int j=m1+1;j<=m;j++)g[j]=x-c[1][1];
for(int i=1;i<=n;i++)f[i]=x;
return ;
}
}
}
bool dp[maxn][maxn];
int B=maxn*maxn;
bitset<maxn*maxn*2> bs[maxn];
void work_sam_dif(){
if(n!=m){
dp[0][0]=1;
int d=abs(m-n);
for(int i=1;i<=m;i++){
for(int j=0;j<d;j++)if(dp[i-1][j]){
dp[i][(j+c[1][i])%d]=1;
dp[i][(j+d-c[1][i]%d)%d]=1;
}
}
vector<int> val(m+1);
int p=0;
for(int i=m;i;i--){
if(dp[i-1][(p+c[1][i])%d])val[i]=-c[1][i],(p+=c[1][i])%=d;
else val[i]=c[1][i],(p+=d-c[1][i]%d)%=d;
}
int sum=0;for(int i=1;i<=m;i++)sum+=val[i];
for(int i=1;i<=n;i++)f[i]=sum/(m-n);
for(int i=1;i<=m;i++)g[i]=f[1]-val[i];
}
else{
bs[0][B]=1;
for(int i=1;i<=m;i++)bs[i]=(bs[i-1]<<c[1][i])|(bs[i-1]>>c[1][i]);
vector<int> val(m+1);
int p=B;
for(int i=m;i;i--){
if(bs[i-1][p+c[1][i]])val[i]=-c[1][i],p+=c[1][i];
else val[i]=c[1][i],p-=c[1][i];
}
for(int i=1;i<=m;i++)g[i]=-val[i];
}
}
void sovle(){
n=read(),m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)b[i][j]=c[i][j]=read();
}
if(n==1&&m==1){puts("0");return ;}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)if(c[i][j]!=c[i][1])p1=i;
}
for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++)if(c[i][j]!=c[1][j])p2=j;
}
if(p1&&p2){
p3=1;for(int j=1;j<=m;j++)if(c[p1][p2]!=c[p1][j])p3=j;
if(!work_dif(c[p1][p2],c[p1][p3])){
if(!work_dif(c[p1][p2],-c[p1][p3])){
if(!work_dif(-c[p1][p2],c[p1][p3])){
if(!work_dif(-c[p1][p2],-c[p1][p3]))puts("Wa work_dif");
}
}
}
}
else if(!p1&&!p2)work_sam();
else{
bool fl=0;
if(!p1){
fl=1;
swap(p1,p2);
for(int i=1;i<=max(n,m);i++){
for(int j=1;j<i;j++)swap(c[i][j],c[j][i]);
}
swap(n,m);
}
work_sam_dif();
if(fl){
for(int i=1;i<=max(n,m);i++){
for(int j=1;j<i;j++)swap(c[i][j],c[j][i]);
}
swap(n,m);
swap(f,g);
}
}
get();check();
}