线性基 学习笔记

做什么都能遇到线性基,于是被迫营业 (你好像之前就写过模板啊

定义及基础操作

线性基(这里只讲异或线性基)就是一个所含数字个数最少的集合,使得原集合中的任意元素都可以用线性基中的若干元素的异或和表示。

一些性质:

  • 原集合中的任意元素都可以用线性基中的若干元素的异或和表示(见定义);
  • 线性基中任意数异或和不为 0 0 0(否则不满足集合大小最小);
  • 以任意顺序枚举原集合中元素,所得集合大小相同;
  • 若线性基大小为 s s s,则一共能表示出 2 s 2^s 2s 个数;若线性基中存在二进制第 i i i 位为 1 1 1 的数,则该线性基共能表示出 2 s − 1 2^{s-1} 2s1 个二进制第 i i i 位为 1 1 1 的数。

插入

用数组 p p p 表示线性基,将 x x x 插入线性基时,从高到低枚举 x x x 的每一位,如果 x x x 的第 i i i 位是 1 1 1,且 p [ i ] = 0 p[i]=0 p[i]=0,那么令 p [ i ] = x p[i]=x p[i]=x 并结束插入;否则 x ← x   x o r   p [ i ] x\gets x\ xor\ p[i] xx xor p[i],继续枚举第 i − 1 i-1 i1 位。

inline void insert(int x){
	for(int i=50;i>=0;--i) if(x&(1ll<<i)){
		if(!p[i]){p[i]=x;break;}
		else x^=p[i];
	}
}

求异或最大值

求原集合子集的异或和最大值,可以考虑贪心,从高到低位枚举线性基中元素,若 a n s   x o r   p [ i ] > a n s ans\ xor\ p[i]>ans ans xor p[i]>ans,则 a n s ← a n s   x o r   p [ i ] ans\gets ans\ xor\ p[i] ansans xor p[i]

inline int qmax(){
	int ans=0;
	for(int i=50;i>=0;--i){
		if((ans^p[i])>ans) ans^=p[i];
	}
	return ans;
}

求异或最小值

分类讨论:

  • 线性基大小 < < < 原集合大小,则原集合中存在一些数异或和为 0 0 0,答案为 0 0 0
  • 线性基大小 = = = 原集合大小,问题可以转化为在线性基中求异或最小值,又由于线性基中最小元素异或任意其它元素,得到的值一定更大,故答案为线性基中最小元素。

求异或 k 小值

思想是改造线性基,使得 ∀ i < j   ( p i   x o r   p j > p i ) ∧ ( p i   x o r   p j > p j ) \forall_{i<j}\ (p_i\ xor \ p_j>p_i)\land (p_i\ xor\ p_j>p_j) i<j (pi xor pj>pi)(pi xor pj>pj),左边的柿子是一定成立的,而右边的柿子成立就需要对于任意在线性基中的 p i p_i pi ∀ j > i   p j   b i t a n d   2 i = 0 \forall_{j>i}\ p_j\ bitand\ 2^i=0 j>i pj bitand 2i=0。在改造完的线性基上求第 k k k 小就只需要将 k k k 二进制拆分就能得到了。

inline ll query(ll k){
    if(n!=siz) --k;
    if(k>(1ll<<siz)-1) return -1;
    ll ans=0;
    rep(i,1,siz) if(k&(1ll<<i-1)) ans^=b[i];
    return ans;
}
inline void solve(){
    n=read(),siz=0;
    rep(i,1,n) a[i]=read(),ins(a[i]);
    Rep(i,0,62) if(p[i]){
        rep(j,i+1,62) if(p[j]&(1ll<<i)) p[j]^=p[i];
    }
    rep(i,0,62) if(p[i]) b[++siz]=p[i];
    m=read();
    while(m--){
        ll k=read();
        printf("%lld\n",query(k));
    }
}

在线删除

依然分类讨论:

  • x x x 不在线性基内,直接删;

  • x x x 在线性基内:假设一个数 i i i 插入的过程中异或的线性基的集合为 S ( i ) S(i) S(i)

    • 若有一个线性基外的数 y y y 使得 x ∈ S ( y ) x\in S(y) xS(y),那么用 y y y 代替 x x x 之后线性基不变,所以删除 x x x 等价于删除 y y y
    • 否则必须删除 x x x,并且要考虑 x x x 对线性基上其它数的影响。假设 y y y 为线性基内满足 x ∈ S ( y ) x\in S(y) xS(y) 的最小元素,对于其它 x ∈ S ( z ) x\in S(z) xS(z) z ← z   x o r   y z\gets z\ xor\ y zz xor y,再将 y y y 替换为 y   x o r   x y\ xor\ x y xor x 即可。

一些例题

[WC2011]最大XOR和路径

传送门

双倍经验

1 1 1 走到 n n n,走的是一条 1 → n 1\to n 1n 的链,链旁边可能挂着若干个环,我们可以在其中选取一些环经过。根据异或的性质,链 → \to → \to 链的过程中链到环的路径走了两遍,贡献异或和为 0 0 0,所以我们只需考虑链上和环上的贡献即可。

那么把每个环的权值异或和加入线性基即可求出最大值。

但是 1 → n 1\to n 1n 有很多条路径怎么办?那必然会构成很多环,另外的链可以由当前链异或环得到。

有的环之间有公共边找不全怎么办?显然异或可以消去公共边的贡献,即若干个小环可以表示一个大环的贡献。同理,小环的贡献也可以由大环异或其它小环表示出。

Xor-matic Number of the Graph

传送门

这道题或许主要在于对线性基性质的更深入理解(?

借鉴上一题的思想,在原图上任意找一棵生成树,将环全部扔进线性基,设 d i s [ x ] dis[x] dis[x] 表示 x x x 到根的距离, k k k 为线性基能表示的数,则要求的就是 ∑ k ∑ 1 ≤ u < v ≤ n d i s [ u ]   x o r   d i s [ v ]   x o r   k \sum\limits_{k} \sum\limits_{1\le u<v\le n} dis[u]\ xor\ dis[v]\ xor\ k k1u<vndis[u] xor dis[v] xor k

枚举点无从下手,考虑枚举每一个二进制位的贡献:假设当前考虑到第 i i i 位,线性基大小为 s s s

  • 若线性基中存在第 i i i 位为 1 1 1 的数,那么根据前面所述的性质,有 2 s − 1 2^{s-1} 2s1 个数第 i i i 位为 1 1 1 2 s − 1 2^{s-1} 2s1 个数第 i i i 位为 0 0 0,所以不论 d i s [ u ] dis[u] dis[u] d i s [ v ] dis[v] dis[v] 在第 i i i 位的情况如何,都会有 2 s − 1 2^{s-1} 2s1 种选择产生贡献。

  • 若线性基中不存在第 i i i 位为 1 1 1 的数,产生贡献当且仅当 d i s [ u ] dis[u] dis[u] d i s [ v ] dis[v] dis[v] 其中一个的第 i i i 位为 1 1 1,可以预处理 d i s [ x ] dis[x] dis[x] 的第 i i i 位为 1 1 1 x x x 的个数 c [ i ] c[i] c[i],则共有 c [ i ] × ( n − c [ i ] ) c[i]\times (n-c[i]) c[i]×(nc[i]) u u u v v v 的组合满足条件。

a n s = ∑ i = 0 b i t m a x ( C n 2   2 s − 1 × ( f l a g [ i ] ≠ 0 ) + c [ i ] ( n − c [ i ] ) 2 s × ( f l a g [ i ] = 0 ) ) × 2 i ans=\sum\limits_{i=0}^{bitmax} (C_n^2\ 2^{s-1}\times(flag[i]\ne 0)+c[i](n-c[i])2^s\times(flag[i]=0))\times 2^i ans=i=0bitmax(Cn2 2s1×(flag[i]=0)+c[i](nc[i])2s×(flag[i]=0))×2i

每个连通块分别计算时要清空彻底/fn

albus就是要第一个出场

传送门

一个结论: n n n 个数组成大小为 s s s 的线性基,则能构成 2 s 2^s 2s 种不同的数,每个数出现 2 n − s 2^{n-s} 2ns 次。

证明:首先每个不在线性基中的数都能被唯一地表示成若干线性基中的数异或和的形式。

考虑一个可以被线性基表示的数 x x x,将线性基划分为用来表示 x x x 的数 S 1 S1 S1、不用于表示 x x x 的数 S 2 S2 S2 两个集合。那么对于每一个不在线性基中的数 y y y,将其表示为 S 1 S1 S1 的一个子集 s 1 s1 s1 S 2 S2 S2 的一个子集 s 2 s2 s2(均可以为空)的异或和。那么就有选 s 1 s1 s1(方案 1 1 1)或选 s 2 s2 s2 y y y(方案 2 2 2)两种选法。每个 y y y 的选择之间相互独立,所以共 2 n − s 2^{n-s} 2ns 种选法。

对于相互独立这一点可能存在疑问。比如当 y 1 y_1 y1 对应的 s 1 s1 s1 y 2 y_2 y2 对应的 s 1 s1 s1 之间有交集时,我们已经钦定了 y 1 y_1 y1 选方案 2 2 2 y 2 y_2 y2 对应的 s 1 s1 s1 集合就不能被完整选到。看起来有点凉,但是其实 y 1 y_1 y1 已经贡献完了交集部分, y 2 y_2 y2 只需要把其对应的 s 1 s1 s1 集合的不属于交集部分的数选上就可以了,也是能做到的。所以选择相互独立。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值