神秘算法 —— 线性基求交

线性基求交:设 A,B 为两个线性基,VA,VB 分别为其生成空间,则 VC=VAVB 是一个线性空间,称 AB 两个线性基的交为 C

首先证明 VC 是一个线性空间。其实很显然,对于任意 x,yVC=VAVBx,yVAxyVA,同理 xyVB,从而 xyVAVB=VC

以下是求线性基的交 C 的算法:

首先对线性基 B 进行一些调整(后面会讲),保持其生成空间 VB 不变。
设存在一个线性基 W,满足以下三条性质:

{W={b | bB,bVA}BW={b | bB,bVA}VBWVA={0}

说成人话,就是 W 是线性基 B 中与 VA 有交的那部分,B 中其余部分与 A 线性无关。
那么可以证明,W 即为所求的线性基的交 C

分两步证明 VW=VAVB

  1. 假设存在 uVWuVAVB
    由于 uVB,故此时存在一些 {bi} 满足 biB, bi=u。将这些 bi 分成两部分,前者 W,后者 BW,令前者的异或和为 s,后者为 t,则 sVW,tVBW
    uVA,sVWVA,故 t=usVA。又 tVBW,由性质 3 得 t=0,从而 u=sVW,矛盾。
  2. 假设存在 uVWuVAVB
    组成 u 的基底既在 B 中也在 VA 中,显然矛盾。

现在我们剩下的问题就剩下求出 W 了。

对每个 bi 依次执行以下操作:

  • bispan({a1,a2,,an,b1,b2,,bi1}),设其表示为 bi=αβ,其中 αVA,βspan{b1,,bi1},令 bibiβ,并标记其为 1 类;
    否则,不做任何操作,标记其为 2 类。

最终得到的 {bi}VA 的交即为满足条件的 W。以下证明其满足 VBWVA={0}

发现经过前面的操作,所有 1 类的 biVA,所有 2 类的 biVA。于是 1bi 所组成的集合即为 W2 类即为 BW

若存在 u0 满足 uVBWuVA,则存在若干个 2bi 以及若干个 ai 使得 bi=u=ai,取出这些 bi 中下标最大的那个 bk,则 bk=b1b2bk1ai,与在位置 kbk 没有标记为 1 类矛盾!

证毕。

代码实现如下:

其中 tA 数组代表 {a1,,an,b1,,bk1} 所形成的线性基,tmp 数组代表线性基的每个位置上 a 中数贡献的异或和,即注意每个基底可表示为 ai1ai2aipbj1bj2bjqtmp 存的即为 ai1ai2aip。新插入数时 u 为当前 bi 剩下的值,cur 代表当前已异或上的 a 中的数,便于更新。

class LinearBase{
public:
    ull base[64];
    LinearBase() { memset(base,0,sizeof(base)); }
    inline bool insert(ull x){
        Rev(i,63,0) if((x>>i)&1) { if(base[i]) x^=base[i]; else { base[i]=x; For(j,i+1,63) if((base[j]>>i)&1) base[j]^=base[i]; ; For(j,0,i-1) if((base[i]>>j)&1) base[i]^=base[j]; ; return true; } } ; return false;
    }
    inline bool count(ull x){
        Rev(i,63,0) if((x>>i)&1) { if(base[i]) x^=base[i]; else return false; } ; return true;
    }
    inline bool operator== (const LinearBase& rhs) { For(i,0,63) if(base[i]!=rhs.base[i]) return false; ; return true; }
    friend inline LinearBase Union(const LinearBase& A,const LinearBase& B){
        LinearBase C,tA=A; ull tmp[64]; memcpy(tmp,A.base,sizeof(tmp));
        For(i,0,63) if(B.base[i]){
            ull u=B.base[i],a=0; int ok=1;
            Rev(j,i,0) if((u>>j)&1){
                if(tA.base[j]) u^=tA.base[j],a^=tmp[j];
                else { ok=0; tA.base[j]=u; tmp[j]=a; break; }
            }
            if(ok) C.insert(a);
        }
        return C;
    }
};

本文作者:CharlieVinnie

本文链接:https://www.cnblogs.com/Charlie-Vinnie/p/17084753.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   CharlieVinnie  阅读(578)  评论(3编辑  收藏  举报
历史上的今天:
2022-02-02 线段树历史区间最值小记🐤
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起