线性基总结
线性基三个性质:
- 原序列里面的任意一个数都可以由线性基里面的一些数异或得到。
- 线性基里面的任意一些数异或起来都不能得到0
- 线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的
构造:arr数组为线性基数组,x为要插入的元素。
void add(ll arr[],ll x) { for (int i = 63; i >= 0; i--) { if (x & (1ll<<i)) { if (arr[i]) x^=arr[i]; else { arr[i] = x; } } } }
arr数组中存的元素arr[i]为二进制最高位1在第i+1位,如果这个位置已经有值了的话就对异或之后的值进行判断。
可用于求一组数异或后的最大值:
ll work() { ll ans=0; for(int i=63;i>=0;i--) if((ans^d[i])>ans) ans^=arr[i]; return ans; }
也可用于求一组数异或后的最小值:
ll work() { for (int i = 0; i <= n; i++) { if (arr[i]) return arr[i]; } }
求第k小:
void work()//处理线性基 { for(int i=1;i<=60;i++) for(int j=1;j<=i;j++) if(d[i]&(1<<(j-1)))d[i]^=d[j-1]; } ll k_th(ll k) { if(k==1&&tot<n)return 0;//特判一下,假如k=1,并且原来的序列可以异或出0,就要返回0,tot表示线性基中的元素个数,n表示序列长度 if(tot<n)k--;//类似上面,去掉0的情况,因为线性基中只能异或出不为0的解 work(); ll ans=0; for(int i=0;i<=60;i++) if(d[i]!=0) { if(k%2==1)ans^=d[i]; k/=2; } }
题目明天再写~
模板题
更多好题(难度非递增):
BJWC 2011 元素 | 题解
SCOI 2016 幸运数字 | 题解
TJOI 2008 彩灯
参考:https://blog.csdn.net/a_forever_dream/article/details/83654397