wrpwrp
2020-06-15 16:03:23
upd:补了点东西
没用我学这东西干嘛
这么点?
还有点性质在下面 可能有点用
由于我想写简单一点,直接对代码写,所以真正的关于线性代数的那一部分就没写了 妄图掩盖自己不会的事实
以下
先贴代码
把一个数插入线性基:
inline void ins(LL x) {
for(R int i=62;i>=0;i--)
if(x&(1LL<<i)) {
if(!p[i]) { p[i]=x,cnt++; break; }
else x^=p[i];
}
}
人话描述:
那么,通过观察这个构造,我们再来感性理解线性基。
于是我们初步理解了线性基
从高到低,如果这一位为
inline int ask(LL x) {
for(R int i=62;i>=0;i--)
if(x&(1LL<<i)) x^=p[i];
return x==0;
}
按位贪心即可。
inline LL askmx() {
LL ans=0;
for(R int i=62;i>=0;i--)
if((ans^p[i])>ans) ans^=p[i];
return ans;
}
其实异或的最小值一般来说就是线性基里的最小元素,因为插入这个元素的时候我们总是尽量让它的高位为
inline LL askmn() {
if(zero) return 0;
for(R int i=0;i<=62;i++)
if(p[i]) return p[i];
}
这个东东我感觉实现还是有那么点点复杂的哈。
首先考虑,要是每一位的选择都不会影响下一位的话,那就可以直接从高到低按位去选择就行了,就类似于二叉树求
inline void rebuild() {
cnt=0;top=0;
for(R int i=MB;i>=0;i--)
for(R int j=i-1;j>=0;j--)
if(p[i]&(1LL<<j)) p[i]^=p[j];
for(R int i=0;i<=MB;i++) if(p[i]) d[cnt++]=p[i];
}
那么这是在干啥呢,就是在尽力把每个
但有时候并不能达到这个样子,可能会出现如下情况:
但是这个时候我们注意到,我们的目的已经达到了,互不影响的任务已经达成了,显然此时为
inline LL kth(int k) {
if(k>=(1LL<<cnt)) return -1;
LL ans=0;
for(R int i=MB;i>=0;i--)
if(k&(1LL<<i)) ans^=d[i];
return ans;
}
其实我个人觉得这个代码还得要自己理解一下。
背板子也行
但是这样其实还不太对,因为我们并没有考虑
printf("%lld\n",tmp-zero?kth(tmp-zero):0LL);
inline int rank(LL x) {
int ans = 0;
for(R int i = cnt - 1; i >= 0; i --)
if(x >= d[i]) ans += (1 << i), x ^= d[i];
return ans + zero;
}
注:这个
于是线性基的基本操作就结束啦!
Luogu P3812 线性基 code
Luogu P3857 [TJOI2008]彩灯 code
Luogu P4301 [CQOI2013]新Nim游戏 code
Luogu P4570 [BJWC2011]元素 code
HDU 3949 XOR code
Luogu P4151 [WC2011]最大XOR和路径 code
Luogu P3292 [SCOI2016]幸运数字 code
dalao博客