线性基

时间:2021-07-25
本文章向大家介绍线性基,主要包括线性基使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

线性基

见到了活的wxy和dsr,激动,激动,激动。

定义:

线性基是一个数的集合,取线性基中若干个数异或起来可以得到原序列中的任何一个数。

线性基三大性质:

  1. 原序列里面的任意一个数都可以由线性基里面的一些数异或得到。
  2. 线性基里面的任意一些数异或起来都不能得到 \(0\)
  3. 在保持性质一的前提下,数的个数是最少的。

构造

举个栗子

原序列: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;
}

洛谷 3812 线性基【模板】

/*
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;
}

原文地址:https://www.cnblogs.com/yangchengcheng/p/15059023.html