线性基
见到了活的wxy和dsr,激动,激动,激动。
定义:
线性基是一个数的集合,取线性基中若干个数异或起来可以得到原序列中的任何一个数。
线性基三大性质:
- 原序列里面的任意一个数都可以由线性基里面的一些数异或得到。
- 线性基里面的任意一些数异或起来都不能得到 (0)。
- 在保持性质一的前提下,数的个数是最少的。
构造
举个栗子
原序列:1 3 4 5
二进制:001 011 100 101
线性基:1 3 4
(d) 数组为序列的线性基,如果 (d[i]) 不为 (0), 则二进制下(d[i])的第 (i + 1) 位一定为 (1),,如果满足 $ a xor b xor c = 0 $ , 那么 (a xor b = c), 那么 (a xor c = b)。
void add(ll x)
{
for(int i = 62; i >= 0; i--)
{
if(x & (1ll << i))
{
if(d[i]) x ^= d[i];
else { d[i] = x; break; }
}
}
}
可以手摸一下,不能成功插入的是其他数能够异或的到的,剩下的可以插入。
求异或最大值
贪心的思想,从最高位开始。
ll query()
{
ll ans = 0;
for(int i = 62; i >= 0; i--)
if((ans ^ d[i]) > ans) ans ^= d[i];
return ans;
}
/*
Date:2021.7.25
Source:luogu 3812
konwledge: 线性基模板
*/
#include <iostream>
#include <cstdio>
#define orz cout << "AK IOI"
#define ll long long
using namespace std;
inline ll read()
{
int f = 0, x = 0; char ch = getchar();
while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while(isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
inline void print(int X)
{
if(X < 0) {X = ~(X - 1); putchar('-');}
if(X > 9) print(X / 10);
putchar(X % 10 + '0');
}
int n;
ll a[55], d[55 * 3];
void add(ll x)
{
for(int i = 62; i >= 0; i--)
{
if(x & (1ll << i))
{
if(d[i]) x ^= d[i];
else { d[i] = x; break; }
}
}
}
ll query()
{
ll ans = 0;
for(int i = 62; i >= 0; i--)
if((ans ^ d[i]) > ans) ans ^= d[i];
return ans;
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n = read();
for(int i = 1; i <= n; i++)
{
scanf("%lld", &a[i]);
add(a[i]);
}
printf("%lld", query());
return 0;
}
例题
4570 元素 哈哈,只有这一道