P10644

Public NOIP Round #8 D. 矩阵

大量证明缺失,只有构造方法。参考 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();
}