题意:
有一个n*m的矩阵,可以放入0或1,现在已经有k个格子放好了0或1,要把矩阵放满,要求是矩阵中每个2*2的格子有奇数个1。输入n、m和已经放了的格子,求方案数。
题解:
首先要介绍位运算中的异或(^)的一个性质:a^b^a=b;
把格子中的点的关系用异或运算来关联。观察下面的表格:
由题意可知,任意四个格子的异或值为1,即
A^B^C^D=C^D^E^F=E^F^G^H=…=1;
选取相邻的两式异或,得
A^B^E^F=0;
A^B^G^H=0;
由此推广,设A(1,1), B(2,1), C(1,j), D(i,1);
- C、D在奇数列上,则 A^B^C^D=0; E^F^G^H=0; 由上下相邻两行不断异或得到: A^C^F^H=0;
即A^H=C^F; - C、D在偶数列上,则 A^B^C^D=1; E^F^G^H=1; 这回不太一样,因为1^1=0, 0^1=1,继续分类讨论:
①当H在偶数行时 A^C^F^H=1; 即1^A^H=C^F;
②当H在奇数行时 A^C^F^H=0; 即A^H=C^F;
综上,对于任意的H(i,j):
if(i%2==0 && j%2==0) 1^(1,1)^(i,j)==(1,j)^(i,1);
else (1,1)^(i,j)==(1,j)^(i,1);
这样就把题目条件转化成了对(1,j)和(i,1)的约束,而(1,1)如果未给出,是需要枚举两种情况的。这样的约束让人想到用并查集来操作,即x^y==0时Union(x,y)、Union(x’,y’);x^y==1时Union(x,y’)、Union(x’,y);其中,x’、y’是x、y的虚点。
注意判断无解情况:x与x’属于同一集合。
经过以上的合并,最后会得到连通块的个数sum(包括虚点),这时再枚举所有的已知点,把他们所在的连通块去除(注意要把(1,1)算入已知因为是枚举的)。剩下的sum’就