线性基

发布时间 2023-12-04 21:08:12作者: zzzzzz2

问题
洛谷P3812
给定一个长度为\(n\)的序列,值域\(2^50\),求在序列中选出若干个数的异或和最大值。
思路:
使用线性基,流程为,枚举\(n\)个数,每个数从二进制最高位向低位枚举,如果这个数含有这一位且这一位未放入任何数,直接放入,如果这个数有这一位但是放入了数,这个数就异或上已经放入的数。
首先证明原序列中的数能异或出的异或和和线性基中的完全等同,因为线性基的数都是原序列异或出来的,所以线性基中能组成的异或和原序列也可以,又因为在刚才的流程中原序列中的数不断地被线性基中的数异或,所以原序列中的数都可以被线性基的异或和表示,综上所述,原序列中的数能得出的异或和和线性基中的完全等同。
得到线性基数组\(a\),其有一个性质,\(a_i\)要么为\(0\),要么最高位为第\(i\)为,可以理解为流程中放不进去就异或是删掉最高位。
贪心每次找最高位让它为一。
代码

#include<iostream>
#define int long long
using namespace std;
int n;
int a[100];
int b[100];
int ans=0;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=60;j>=0;j--){
			if((a[i]&(1ll<<j))!=0){
				if(b[j]==0){
					b[j]=a[i];
				}
				a[i]^=b[j];
			}
		}
	}
	for(int j=60;j>=0;j--){
		if(b[j]!=0&&(ans&(1ll<<j))==0){
			ans^=b[j];
		}
	}
	cout<<ans;
	return 0;
}