[USACO11NOV]Binary Sudoku G 题解
定义一个 \(3\times3\) 的表格 \(a\),表示每个小九宫格内 1 的个数的奇偶状态。
再定义两个长为 \(9\) 的数组 \(c0,c1\),表示每行每列上 1 的个数的奇偶状态。
当 \(d_{i,j}\) 取反时,会将 \(a_{[\frac{i}{3}],[\frac{j}{3}]},c0_i,c1_j\) 各取反一次。
要将 \(a_{i,j}\) 全部变为 0,\(a\) 内 1 的个数是至少需要取反的次数。
将 \(c0,c1\) 各划分为三块,每三个数一块。
若 \(a_{i,j}\) 取反了,则 \(c0\) 的第 \(i\) 块中的某个数和 \(c1\) 的第 \(j\) 块中的某个数也会取反。
我们优先选择块中为 1 的取反,如果没有 1 就统一将块中的第一个数取反。
最终 \(a_{i,j}\) 全部变为 0 了,但是题目还要求将 \(c0_i\) 和 \(c1_i\) 全部变为 0,可以证明,这时 \(c0\) 和 \(c1\) 的每个块中只会有偶数个 1。所以这时候 \(c0\) 和 \(c1\) 内 1 的个数的最大值就是要再取反的次数。
时间复杂度:输入的时间复杂度。
代码:
#include<iostream>
#define rept(i,a,b) for(int i=a;i<b;++i)
using namespace std;
int ans,num1,num2;
bool a[3][3],c0[9],c1[9];
char ch;
signed main(){
rept(i,0,9)rept(j,0,9){
cin>>ch;
if(ch=='1'){
a[i/3][j/3]^=1;
c0[i]^=1,c1[j]^=1;
}
}
rept(i,0,3)
rept(j,0,3)if(a[i][j]){
rept(k,i*3,i*3+3)if(c0[k]){
c0[k]^=1;
goto next1;
}
c0[i*3]^=1;
next1:;
rept(k,j*3,j*3+3)if(c1[k]){
c1[k]^=1;
goto next2;
}
c1[j*3]^=1;
next2:;
ans++;
}
rept(i,0,9)num1+=c0[i],num2+=c1[i];
cout<<ans+max(num1,num2);
return 0;
}