线性基进阶

基础知识

  • 不管在实数意义下,还是在模 \(2\) 意义下,线性基的作用都是体现 \(n\) 维向量之间的表示关系,这是最本质的用途
    如果一个向量可以插入到当前的线性基中,那么代表其不能由当前基中的向量表示,否则可以
    即每个在基中的向量都是线性无关的
    在模 \(2\) 意义下,可以用来判定是否有子集异或和为零

DZY Loves Chinese II

这道题确实是将异或的性质运用到了极致
首先求出原图的一个 \(dfs\) 树,考虑一条树边连接的两个点如果变得不连通意味着这条边以及跨过这条边的所有返祖边都被割断
那么为了刻画这种性质,可以对与每一个返祖边都分配一个随机数作为特征值,把其覆盖的一段区间都异或上它的值
此时限制条件成功转化为判断是否有一个边集异或和为零,用线性基维护即可


开学前的涂鸦

这回 得寸进尺 需要求方案数了
可以发现其实另外的 \(k\) 条边和原本的边是无差别的,于是混在一块建树并挑出新的 \(k\) 条返祖边
发现 \(k\) 非常小,那么其实不同的边最多只有 \(2k\) 种取值
而相同取值的边其实是没有区分的,可以看成加权下的一种边
对于这些边的组合进行 \(dfs\),过程中动态维护线性基判断能不能加入即可


清扫银河

另一个套路
首先设一个点的权值为周围边权异或和,此时一个图的割相当于一个点集的权值异或和
即一边点集内的边权被相互抵消,不同点集间的边权才能生效
对于操作 \(1\),选择一个环进行操作一个点边权和的奇偶性不会发生改变
但是对于任意一种点权和为偶数的情况都可以经过一系列操作转化为合法的
由于此时只与每个点度数的奇偶有关,所以以此来记录状态
由于操作数足够,那么将每个点作为割的一个集合进行操作,将形成的状态放入线性基,看看能不能将初始状态作用成零


  • 设线性基大小为 \(|S|\),向量总数为 \(x\),那么这个基可以表示出的向量数为 \(2^{|S|}\),每个可以被表示出来的向量有 \(2^{|S|-cnt}\) 中表示方法
    根据这一结论可以解决相关计数问题

CF895C Square Subsets

比如说这道题,分析发现平方数的特点就是所有质因子出现次数为偶数
换句话说模二意义下异或和为零
于是可以想到用线性基维护,将每个数质因数分解的结果 \(01\) 表示为向量然后根据线性基大小代公式即可


P7451 [THUSCH2017] 杜老师

这次是升级版
首先数的值域过于庞大,不能开这么大的维度
运用应对质因数分解的经典 \(trick\):单独记录最大质因子,即大于根号的只有一个
但是数的范围还是过大不允许一个一个插入
“观察”发现线性基其实是非常稠密的,那么当区间过大的时候会使得每一个出现过的质因子都安排进线性基,此时统计出现的质数个数即可
经过实践证明了这个分界点不超过 \(7000\)


  • 关于线性基的合并与数据结构的结合在上一篇中提到就不再多讲

  • 关于线性基的删除与修改

最简单的实现方式是线段树分治,一般适用于离线问题很好实现

但是线性基确实是支持修改的,但是每次修改的复杂度是 \(nm\) 级别的,一般适用于 \(m\) (向量维度)和 \(n\) (向量个数)接近的情况:
首先插入线性基时保存这一向量是由基中哪些向量异或得来的
对于每次删除,如果不在基中,直接删掉即可
否则查看是否存在一个不在基中的向量由当前向量表示,如果存在,那么一定可以将这个向量插入基中来完成删掉的向量之前的任务
否则此时矩阵必须降秩,选出(如果是求最值应当从低位开始选)一个基中的和当前向量有关的向量拿出来删掉
删掉之后同时更新基中其他向量的值与组成

void Xor(int id,bi w){
	int pos=0;
	for(int i=1;i<=p;i++){
		if(val[i].none()&&fr[i][id]){
			pos=i;
			break;
		}
	}
	if(!pos){
		for(int i=1;i<=s;i++){
			if(lb[i]&&fr[lb[i]][id]){
				pos=lb[i];
				lb[i]=0;
				break;
			}
		}
	}
	for(int i=1;i<=p;i++){
		if(i!=pos&&fr[i][id]){
			val[i]^=val[pos];
			fr[i]^=fr[pos];
		}
	}
	val[pos]=w;fr[pos].reset().set(id);
	insert(pos);
	return ;
}

其中注意第 \(24\)行的位置,如果是修改必须重置组成
如果是异或,不需要重置组成
如果是删除,则需要对当前向量打标记


P3733 [HAOI2017]八纵八横

可以发现其实就是在环的经典套路基础上套了一个带修,可以用作练习模板


最大异或和

首先用到一个性质:

一组向量集的张成空间与其差分数组的相同

于是成功将区间修改操作变成差分数组上的单点操作

对于操作二,相当于是进行了多次删除外加两次修改

那么用删除的套路进行维护即可


围绕着我们的圆环

这个转化着实太奇妙了
首先把 \(C\) 矩阵的每列看成一个向量,于是变成了一个列向量的向量集
\(A\) 向量也这样处理,\(B\) 矩阵用于表示每个向量是否使用
那么此时成功转化成用 \(A\) 集合中的向量去拼凑 \(C\) 向量集合的问题
\(A\) 的秩为 \(r\),那么拼凑出 \(C\) 的方案数为 \(2^{s(q-r)}\)
可以发现整个问题中方案数只与对应的矩阵的秩有关,那么以此为状态进行 \(dp\)
\(f[n][m][r]\) 表示一个 \(n\)\(m\) 列的矩阵秩为 \(r\) 的方案数
那么统计答案是考虑枚举 \(A\) 的秩 \(r\) (用 \(x\) 表示 \(C\) 的秩):

\[ans=\sum_{r=x}\frac{f[p][q][r]f[r][s][x]2^{s(q-r)}}{f[p][s][x]} \]

可以发现式子中只与 \(f[p][i][j]\)\(f[s][i][j]\) 有关,那么将这两个状态分别设为 \(f[i][j]\)\(g[i][j]\) 进行 \(dp\)
转移通过分类是否增加矩阵的秩来转移:

\[f[n][i+1][r]=f[n][i][r]2^r \]

\[f[n][i+1][r+1]=f[n][i][r](2^n-2^r) \]

修改操作顺便维护即可

posted @ 2022-08-26 19:54  y_cx  阅读(63)  评论(0编辑  收藏  举报