线性异或方程组实际上是比较常用的,一个经典的例子就是关灯问题,在这里不做累述。
我们形式化的表述这个问题。有$n$个变量,$m$个方程,每一个方程形如:
$$ a_1 x_1 ; xor ; a_2 x_2 ; xor ; a_3 x_3 ; xor ; ... xor ; a_n x_n = b $$
其中$a, b, x$的取值范围都是${0, 1}$。
关于这个方程组,我们通常要求:1)任意一组合法解。2)解的个数。3)最优的解(如字典序第$k$小等)。
普通的高斯消元对于解异或方程组有很大的借鉴意义,我们可以用两个方程的系数异或来消元。但和普通不同的是,因为这里每个变量只有两种取值,所以我们可以算出其解的个数。
首先,我们要对方程组做基本的变换以符合我们的一些想法。
我们要对每个方程引入关键元的概念,定义为每个方程从左到右第一个系数不为$0$的变量。
我们把这些方程看作是逐个添加的过程,并且在这个过程中始终要保持每一个变量最多成为一个方程的关键元,一个变量可以不成为关键元。
我们每次添加一个方程$A$的时候,从左到右枚举每个系数不为$0$的变量。对于当前变量,如果它已经是某一个方程$B$的关键元,那就用$B$来消$A$,消掉这个变量;否则如果$A$还没有关键元,那就把这个变量设成$A$的关键元。易得,如果这个方程没有关键元那方程左边肯定都是$0$,此时看方程右边是否是$0$来判无解,判完就可以扔了;否则我们就用方程$A$去消之前的方程。
很明显,我们在添加方程的过程中始终保持了每一个变量最多成为一个方程的关键元这个条件。假设最终我们得到了$t$个带有关键元的方程,那我们就会有剩余的$s = n - t$个变量不是关键元,我们称他们为自由元。自由元的含义就是不论他们取值如何,剩下的关键元总可以得到唯一一组解。从形式上来看的确如此,每一个自由元并不会影响别的,改变的相当于只是方程右边的$b$而已。
有经验的读者可能会发现,这里的处理方法和线性基十分相似。
接着我们来考虑之前那些问题如何解决。
1)求任意一组解现在来说是十分容易的,我们只要随便选择自由元的取值,然后带到方程中去即可。
2)由于自由元的任意一组取值都能导出关键元的唯一一组解,所以解的个数就是$2^s$。
3)以求字典序第$k$为例。我们用通常的逐位确定的思路来做。我们从小到大枚举每一个变量,并且用$now$表示目前方程中自由元的个数。如果当前变量$x$是自由元,那不管$x$取什么,剩下的解数总是$2^{now - 1}$,据此可以确定$x$的值,然后$k -= 2^{now - 1},--now$。如果当前变量$x$是关键元,并且方程左边就它一个变量,显然它的值是固定的,$continue$就行了。否则就是说除了它还有其他变量,找到关键元右边的第一个系数为$1$的变量$y$,可知$y$一定是自由元(如果它是关键元就会被别的方程消掉),假设我们任意确定了$x$的值,然后就把$y$当成关键元,这样之后自由元个数就会减一,所以在这个$case$中我们同样只要判断$2^{now - 1}$来确定$x$的取值,然后把$y$当成该方程的关键元就行了,$k -= 2^{now - 1}, --now$。