线性基学习笔记

这个东西的作用在于:

  • 快速求一个数能否被一些数异或得到

  • 求一些数中任选几个数的异或最大值、最小值

  • 求一些数中的异或第 k 大值

它有如下性质:

  • 原数列中的所有数都可以通过线性基里的数异或出来

  • 任意子集异或和不为0

  • 一个数列可能有多个线性基,但是线性基里数的数量一定唯一,而且是满足性质一的基础上最少的

操作

插入

假设当前插入的值为 \(x\)\(x\) 的最高位为 \(i\):

  • 如果当前位是空的,直接插入 \(x\)

  • 如果当前位已经有数 \(a_i\),那么令 \(x=a_i \oplus x\),重复此过程,直到 \(x=0\)

如果 \(x=0\),就证明可以表示,否则就要加新数

用这个方法,可以确定一个数能否被表示

求最值

先看最小值,因为线性基位数是不断变多的,所以最小值异或上什么都必然增加,所以最小值就是线性基中的最小值

接下来是最大值,可以顺序跑,如果当前位是 0,就异或 \(a_i\),这样一定会更大

例题

线性基模板

https://www.gxyzoj.com/d/gxyznoi/p/54

就是求最值,注意 long long

点击查看代码
#include<cstdio>
#define ll long long
using namespace std;
int n;
ll a[60];
void insert(ll x)
{
	for(int i=51;i>=0;i--)
	{
		if(x&(1ll<<i))
		{
			if(!a[i])
			{
				a[i]=x;
				break;
			}
			else x^=a[i];
		}
	}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		ll x;
		scanf("%lld",&x);
		insert(x);
	}
	ll ans=0;
	for(int i=51;i>=0;i--)
	{
		if(ans&(1ll<<i)) continue;
		ans^=a[i];
	}
	printf("%lld",ans);
	return 0;
}

[BeiJing2011] 元素

https://www.gxyzoj.com/d/gxyznoi/p/P47

显然的,假设当前数为 x,如果 x 能加入之前已选元素的基中,x 就可以被选

所以可以将值从大到小排序,然后依次插入判断即可

albus就是要第一个出场

https://www.gxyzoj.com/d/gxyznoi/p/P48

一个性质,如果线性基中有 s 个数,总共有 n 个数,那么能组成 \(2^s\) 个数,每个数 \(2^{n-s}\)

所以因为是大小,所以根据有 1 的位置,计算在这 \(2^s\) 个数的排名即可

玛里苟斯

https://www.gxyzoj.com/d/gxyznoi/p/P49

根据答案的范围,可以发现,当 \(k\ge 3\) 时,至多有 \(2^{21}\) 种不同的数

所以当 \(k\ge 3\) 时,直接建出线性基暴搜即可

对于 k=1,如果所有数的第 i 位存在 1,那么就有 \(\frac{1}{2}\) 的概率异或后为 1

对于 k=2,假设当前数为 \(x=2^{a_1}+2^{a_2}+\dots\),那么 \(x^2=\sum_{i=1}^{len}\sum_{j=1}^{len} 2^{i+j}*f(i,j)\)

这里的 \(f(i,j)\) 就是两者同为 1 的概率

如果所有数字中的两位都相同,就是 \(\frac{1}{2}\),否则就是 \(\frac{1}{4}\)

DZY Loves Chinese II

好吧,是构造

先考虑最简单的情况,就是判断一个点和其他点的连通性

那么如果使用异或的思想,判断有没有断干净,就是使得跟这个点相连的所有边的异或和为 0

继续推广,可以发现,只要满足上面的条件满足时,就可以判断一个边集是否能断开

所以接下来是构造方法,可以任意 dfs 一个生成树,如果与 i 连通的边未被赋值,树边访问,非树边随机即可

shallot

https://www.gxyzoj.com/d/gxyznoi/p/P51

因为每一次删除都会导致后面加入的全部重做,所以要尽量避免删除操作

如果将每一次操作都标上时刻,那么每个数存在的就是一个时间段

那么可以枚举时间,然后加入存在的数,可以线段树分治优化

[BeiJing2011]梦想封印

https://www.gxyzoj.com/d/gxyznoi/p/P52

显然的,删边难做,倒过来加边

可以发现,最终的东西简化后就是先以 1 为根建立生成树,组成是一些环+一条链

因为环不受限制,为了统计情况数,可以建立线性基

接下来是如何对链去重,因为异或后最小值为 x 的两个数,其他得到的数必然相同

所以可以用 set,储存不同的最小值

[SCOI2016] 幸运数字

https://www.gxyzoj.com/d/gxyznoi/p/P53

题目可以转化为求这条路径上的线性基

显然,线性基是可以合并的,所以可以倍增,记录每一段的线性基,然后求解时跳 LCA 即可

Shortest Path Queries

https://www.gxyzoj.com/d/gxyznoi/p/P938G

看到删除,线段树分治,对于环,扔进线性基,接下来是如何求树边链长的问题

涉及到联通块,考虑可撤销并查集,连边的时候因为是父亲和父亲连边,所以要异或上到父亲的权值

posted @ 2025-06-02 17:54  wangsiqi2010916  阅读(26)  评论(0)    收藏  举报