CF1610D题解
前言
上一场 CF(CF1860)构造题炸了,找题做的时候发现的这题。
A 了之后看了眼题解,发现我的解法和题解不太一样。
题解
CF1800,甚至还有个 flow 的标签
文中用 $ mat_{i,j} $ 指代矩阵中 $i$ 行 $j$ 列的数。
第一反应肯定拆数字。
将所有的异或和拆成二进制,则题目变为求 32 个 01 矩阵,使异或和满足行和列的需求。
观察得到的 01 序列,可以发现:
如果行与列序列在这一位上的异或和不等,则一定不存在这样的矩阵,直接输出 NO;
否则只有三种可能性:
行序列和列序列上的 1 一样多,则对每一个 1 从左往右扫一遍,如果找到1就直接将矩阵中该位置变为 1
行序列上的 1 比列序列上的 1 多,则每次扫到 $i$ 下标时如果没扫到 1,则直接将 $ mat_{i,1} $ 变成 1
列序列上的 1 比行序列上的 1 多,则行上扫完以后将列序列中所有仍为 1 的下标 $i$ 的 $mat_{1,i} $ 变成 1
如果有点懵可以自己手动做一下。
答案位移后相加即可。
code
#include <bits/stdc++.h>
using namespace std;
int n,i,j,k,m;
int a[105],b[105];
int ans[105][105];
int ansa[105],ansb[105];
int main() {
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=m;i++)
scanf("%d",&b[i]);
for(i=0;i<=30;i++){
int sum1=0,sum2=0;
for(j=1;j<=n;j++){
ansa[j]=a[j]&1;
a[j]>>=1;
sum1^=ansa[j];
}
for(j=1;j<=m;j++){
ansb[j]=b[j]&1;
b[j]>>=1;
sum2^=ansb[j];
}
if(sum1!=sum2){
printf("NO");
return 0;
}
for(j=1;j<=n;j++){
if(ansa[j]==0) continue;
else{
bool flag=false;
for(k=1;k<=m;k++){
if(ansb[k]==1){
ansb[k]=0;
ansa[j]=0;
ans[j][k]|=(1<<i);
flag=true;
break;
}
}
if(flag==false){
ansb[1]=1;
ansa[j]=0;
ans[j][1]|=(1<<i);
}
}
}
for(j=1;j<=m;j++)
if(ansb[j]==1){
ansb[j]=0;
ans[1][j]|=(1<<i);
}
}
printf("YES\n");
for(i=1;i<=n;i++){
for(j=1;j<=m;j++)
printf("%d ",ans[i][j]);
printf("\n");
}
return 0;
}