说明
先说明一下这里的求交与求并分别是什么意思。就是有两个线性空间
V
1
V_1
V1与
V
2
V_2
V2,求出这两个空间的交与并。当然OI中的线性空间大部分是指异或操作下的,也就是常说的线性基。
如下所说的,都是异或的线性基,不区分加号与异或,即
∑
x
i
=
x
1
⊕
x
2
.
.
.
⊕
x
3
\sum x_i = x_1 \oplus x_2 ... \oplus x_3
∑xi=x1⊕x2...⊕x3。
当然可以扩展到任意线性空间,大致方法不变。
求交
明显答案也是一个线性基。
那么我们还需要如下引理:
设
{
α
i
=
1
−
x
}
\{\alpha_{i= 1 - x}\}
{αi=1−x}是
V
1
V_1
V1的一组线性基,
{
β
i
=
1
−
y
}
\{\beta_{i= 1 - y}\}
{βi=1−y}是
V
2
V_2
V2的一组线性基。设
W
W
W是
{
β
}
\{\beta\}
{β}中在
V
1
V_1
V1的基,如果
α
⋃
{
β
∖
W
}
\alpha \bigcup\{\beta \setminus{W}\}
α⋃{β∖W}线性无关,那么
W
W
W就是交的线性基。
从而可以得到:
如果
β
i
\beta_i
βi能被
{
α
i
=
1
−
x
}
\{\alpha_{i=1-x}\}
{αi=1−x}与
β
j
=
1...
i
−
1
\beta_{j = 1 ... i - 1}
βj=1...i−1线性表示出来,我们可以把
⨁
i
=
1
x
α
i
\bigoplus_{i = 1}^{x}\alpha_i
⨁i=1xαi或者
⨁
j
=
1
i
−
1
β
j
\bigoplus_{j=1}^{i-1}\beta_j
⨁j=1i−1βj(注意要么加入
α
\alpha
α要么加入
β
\beta
β)加入答案的线性基中。
代码如下:
LinearBasis Merge(LinearBasis A,LinearBasis B) {
LinearBasis All , C , D;
All.clear();
C.clear();
D.clear();
for (int i = 60;i >= 0;i--) {
All.basis[i] = A.basis[i];
D.basis[i] = 1ll << i;
}
for (int i = 60; i >= 0; i--) {
if (B.basis[i]) {
ll v = B.basis[i] , k = 0;
bool can = true;
for (int j = 60; j >= 0; j--) {
if (v & (1ll << j)) {
if (All.basis[j]) {
v ^= All.basis[j];
k ^= D.basis[j];
} else {
can = false;
All.basis[j] = v;
D.basis[j] = k;
break;
}
}
}
if (can) {
ll v = 0;
for (int j = 60; j >= 0; j--) {
if (k & (1ll << j)) {
v ^= A.basis[j];
}
}
C.insert(v);
}
}
}
C.build();
return C;
}
同样的,如下代码也可以:
LinearBasis Merge(LinearBasis A,LinearBasis B) {
LinearBasis All , C , D;
All.clear();
C.clear();
D.clear();
for (int i = 60;i >= 0;i--) All.basis[i] = A.basis[i];
for (int i = 60; i >= 0; i--) {
if (B.basis[i]) {
ll v = B.basis[i] , k = 1ll << i;
bool can = true;
for (int j = 60; j >= 0; j--) {
if (v & (1ll << j)) {
if (All.basis[j]) {
v ^= All.basis[j];
k ^= D.basis[j];
} else {
can = false;
All.basis[j] = v;
D.basis[j] = k;
break;
}
}
}
if (can) {
ll v = 0;
for (int j = 60; j >= 0; j--) {
if (k & (1ll << j)) {
v ^= B.basis[j];
}
}
C.insert(v);
}
}
}
C.build();
return C;
}
注意区别。
求并
通过容斥原理将并转化为交即可。