[笔记] 线性基

用处#

  • 快速查询一个数是否可以被一堆数异或出来
  • 快速查询一堆数可以异或出来的最大 / 最小值
  • 快速查询一堆数可以异或出来的第 k 大值

性质#

  • 原数列里的任何一个数都可以通过线性基里的数异或表示出来
  • 线性基里任意一个子集的异或和都不为 0
  • 一个数列可能有多个线性基,但是线性基里数的数量一定唯一,而且是满足性质一的基础上最少的。

实现#

构造
void insert(LL x){
	rfor(i, lim, 0) if(x & (1LL << i)){
		if(a[i]) x ^= a[i];
		else{ a[i] = x; break; }
	}
}
查询一个元素是否可以被异或出来
bool check(LL x) {
	rfor(i, lim, 0) if(x & (1LL << i)) x ^= a[i];
	return x == 0;
}
查询异或最大值

按位贪心.

LL askmax() {
	LL ans = 0;
	rfor(i, lim, 0) if(ans < (ans ^ a[i])) ans ^= a[i];
	return ans;
}
查询异或最小值

一般来说就是线性基里的最小元素,特判 0.

LL askmin() {
	if(zero) return 0;
	lfor(i, 0, lim) if(a[i]) return a[i];
}
查询异或第 k

重建线性基,使得不同位尽量不相互影响。

void rebuild() {
	rfor(i, lim, 0) rfor(j, i - 1, 0) if(a[i] & (1LL << j)) a[i] ^= a[j];
	lfor(i, 0, lim) if(a[i]) p[++cnt] = a[i];
}

类似树状数组二分第 k 小,同样特判 0.

LL kth(int k) {
	LL ans=0;
	rfor(i, lim, 0) if(k & (1LL << i)) ans ^= p[i];
	return ans;
}
查询排名

与查询第 k 小类似.

int rank(LL x) {
	LL ans = 0;
	rfor(i, cnt - 1, 0) if(x >= p[i]) ans += (1LL << i), x ^= p[i];
	return ans + zero; 
}

题目#

[WC2011]最大XOR和路径

1n 的最大XOR和路径可以看作任意一条从 1n 的路径异或上若干个环。

[CQOI2013]新Nim游戏

分析出答案的补集就是线性基。


posted @   IrisT  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩