您的位置:首页 > 理论基础 > 数据结构算法

[学习笔记]省选(算法?数据结构?)·线性基

2018-02-03 15:50 495 查看

一、开头

神犇MX:怎么样?xyz32768,你学不会后缀自动机,真是菜啊!

xyz32768:是啊,我本来就很菜啊!

神犇MX:你不服的话,再考你一道题:给定一个nn个数的数集,求一个子集,使这个子集的xorxor和最大?只需要输出这个xorxor和。n≤105n≤105并且每个数不大于260260。

xyz32768:爆搜子集,O(2n)O(2n),我好像只会这样了。

神犇MX:看来你还是太菜,连线性基都不会,怎么可能会后缀自动机呢?

xyz32768:啊啊啊啊啊啊啊啊啊啊啊啊啊啊……(省略1099999910999999个“啊”)

二、介绍

一个nn个数的正整数集合SS,这个集合的线性基是一个mm个正整数的集合:

A={a1,a2,a3,...,am}A={a1,a2,a3,...,am}

线性基有两点性质:

:如果存在S′⊂SS′⊂S且S′S′内元素的xorxor和为tt,那么就一定存在A′⊂AA′⊂A且A′A′内的元素的xorxor和为tt,反过来也一样。简单的说,通过AA集合内的元素xorxor出的值域与通过SS集合内的元素xorxor出的值域相同。

:线性基还有一个重要的性质:对于任何一个ii,要么aiai不存在,要么aiai最高位的11在第ii位上。

三、构造(插入一个新数)

集合SS为空时,线性基即集合AA的每一个元素(即a1,a2,...a1,a2,...)都不存在。

向线性基中插入新数pp的方法:

从高到低扫描pp的每一个二进制位,扫描到pp的第ii位为11时,分两种情况:

如果aiai不存在,那么令ai=pai=p并且结束扫描。

否则令p=p xor aip=p xor ai并继续扫描。

简单解释:假设插入新数pp之前的线性基为A′A′,设A′A′满足线性基的两个性质,那么在aiai不存在并且pp最高位的11在第ii位的情况下,令ai=pai=p,得到的线性基仍然满足性质。

而在aiai存在的情况下令p=p xor aip=p xor ai是为了使pp的第ii位为00,以此维护性质。这时候pp异或上aiai之后等于待插入的新数,而两个相等的数的异或值总是00,这时候仍然满足线性基的性质

代码(代码中的orzorz表示线性基,orzi=−1orzi=−1就表示orziorzi不存在):

void ins(ll p) {
int i; for (i = m; i; i--) {
if (!((p >> i - 1) & 1)) continue;
if (orz[i] == -1) return (void) (orz[i] = p);
else p ^= orz[i];
}
}


合并两个线性基,就是把一个线性基中的元素暴力插入到另一个线性基里面。

代码:

cyx mer(cyx a, cyx b) {
int i; for (i = m; i; i--)
a.ins(b.orz[i]);
return a;
}


四、查询

1、最大异或和

贪心。从高往低扫aa,对于一个aiai,如果aiai存在,并且异或上aiai后会使结果更大,就异或上aiai。通过性质可以得出正确性。

代码:

ll max_xor() {
int i; ll ans = 0; for (i = m; i; i--)
if ((ans ^ orz[i]) > ans) ans ^= orz[i];
return ans;
}


2、一个数pp能否被异或出

贪心,同样是利用性质。首先记下res=0res=0。从高往低扫aa。

对于一个aiai,如果aiai存在,并且resres的第ii位与pp的第ii位不等,则使res=res xor aires=res xor ai。

如果最后res=pres=p,那么pp能被异或出。当然需要特判00:

如果SS中有00,或者在构建线性基的过程中,存在一个待插入的数kk使得插入之前kk能被异或出,那么存在一个非空子集的异或和为00。

代码(不加特判00):

bool _xor(ll p) {
int i; ll res = 0;
for (i = m; i; i--) {
if (orz[i] == -1) continue;
if (((p >> i - 1) & 1) != ((res >> i - 1) & 1))
res ^= orz[i];
}
return res == p;
}


五、题目

(待补充)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: