H - XOR 线性基

在这里插入图片描述在这里插入图片描述
利用期望的线性性,等价于计算每个数在集合中的方案数
线性基。先建立一个线性空间b,假设会的到r个基底,这r个基底是线性无关的(就是说,r个基底的数值无论怎么取,异或和都无法得到零),而剩下的n-r个数都可通过这r个基底之间异或得到。
要满足异或和等于0的话,就必须从n-r个数里面考虑。
对于这n-r个数,无论怎么取得到的异或和,在r个数中肯定有且只有一种组合方式使得这种组合方式的异或和等于n-r中取得的异或和。假设一个数必须在方案中,剩下的数有2n−r−12^{n-r-1}2nr1种取法,所以ans=n∗(2n−r−1)ans = n * (2^{n-r-1})ans=n(2nr1)种取法。
对于r个基底,n-r个数中可能有可以代替它作为基底的数字。所以对构成r的数值枚举进行判断。(就类似于r个基底中的一个数跟n-r中的数换了一下,那么这个基底也有2n−r−12^{n-r-1}2nr1种方案数)。判断就是根据就是这个基底能不能由其他向量的线性组合出来。如果能就要加上2n−r−12^{n-r-1}2nr1种方案数。
所以每次都用n-r个数和r-1个其他基底构建线性空间,看看枚举的这个基底能否insert到线性空间中。
能就表示该数没有其他数与它线性相关,不能就表示可以由其他向量线性组合出来(就是可以跟n-r个数中的一个进行交换)。
下面是口胡,自己都不知道在说什么
进行枚举的时候枚举的是原来的数值而不是线性空间的基底数值。基底数值有点类似于正交分解后的基向量(比如这道题2≤10182\leq10^{18}21018,转换成二进制一共有61位,每个基底提供的是最高位上的1,有61个向量的话就相当于构成61维的线性空间)所以枚举b空间里的基向量会有问题。口胡结束,希望大佬来指出错误,雾
为了方便,我们先用n-r个数组构建一个线性空间b1,然后枚举基底的时候,就可以在b1上面尝试添加b空间的基向量就可以了

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const ll mod = 1e9+7;

ll qpow(int a,int x)
{
	ll t = a;
	a = 1;
	while (x)
	{
		if (x & 1) a = a * t % mod;
		t = t * t % mod;
		x = x >> 1;
	}
	return a;
}

struct Basis{
	ll basis[61] = {};
	int index[61] = {};
	bool insert(ll x,int num)
	{
		for (int i = 60;i>=0;i--)
		{
			if (x & (1ll<<i))
			{
				if (basis[i] == 0)
				{
					basis[i] = x;
					index[i] = num;
					return true;
				}
				else x = x ^basis[i]; 
			}
		}
		return false;
	}
};

int main()
{
	ll n;
	while (scanf("%lld",&n) != EOF)
	{
		ll a[100010] = {},count = 0;
		Basis b;
		for (int i = 1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
			if (b.insert(a[i],i) == false) count++;
		}
		ll t = qpow(2,count - 1);
		ll ans = count * t % mod;
		ll a1[100010] = {},len = 0;
		for (int i = 0;i<=60;i++)
		{
			if (b.index[i] != 0) 
			{
				a1[++len] = a[b.index[i]];
				a[b.index[i]] = 0;
			}
		}
		Basis b1;
		for (int i = 1;i<=n;i++) b1.insert(a[i],i);
		for (int i = 1;i<=len;i++)
		{
			Basis b2 = b1;
			for (int j = 1;j<=len;j++)
			{
				if (i != j) b2.insert(a1[j],j);
			}
			if (b2.insert(a1[i],i) == false) ans = (ans + t) % mod;
		}
		printf("%lld\n",ans);
	}
}
### 关于线性基的C++实现 线性基是一种用于处理向量空间中线性无关性的数据结构,在许竞赛编程问题中有广泛应用。以下是基于用户需求的一个完整的线性基 C++ 实现代码示例: #### 线性基的核心概念 线性基是一组数,能够通过异或操作表示某个集合内的所有可能数值组合。对于给定的一组整数 \( S \),其线性基可以唯一确定这些整数所能构成的所有 XOR 值。 ```cpp #include <bits/stdc++.h> using namespace std; const int MAX_BITS = 60; // 根据题目范围调整最大位数 struct LinearBasis { long long basis[MAX_BITS]; // 存储线性基数组 void insert(long long x) { // 插入一个新元素到线性基中 for (int i = MAX_BITS - 1; i >= 0; --i) { if (!(x >> i)) continue; if (!basis[i]) { basis[i] = x; break; } x ^= basis[i]; } } bool contains(long long x) const { // 判断某值是否能由当前线性基生成 for (int i = MAX_BITS - 1; i >= 0; --i) { if ((x >> i) & 1 && !basis[i]) return false; x ^= basis[i]; } return true; } long long max_xor() const { // 计算线性基的最大XOR值 long long res = 0; for (int i = MAX_BITS - 1; i >= 0; --i) { if ((res ^ basis[i]) > res) res ^= basis[i]; } return res; } vector<long long> get_all_elements() const { // 枚举线性基可生成的所有不同值 vector<long long> elements{0}; for (int i = 0; i < MAX_BITS; ++i) { if (!basis[i]) continue; int sz = elements.size(); for (int j = 0; j < sz; ++j) { elements.push_back(elements[j] ^ basis[i]); } } sort(elements.begin(), elements.end()); return elements; } }; // 测试部分 void test_linear_basis() { LinearBasis lb; vector<long long> nums = {8, 4, 12}; // 输入一组数 for (auto num : nums) lb.insert(num); cout << "Max XOR value: " << lb.max_xor() << "\n"; // 输出最大XOR值 } ``` 以上代码实现了线性基的主要功能,包括插入、查询是否存在特定值以及计算最大 XOR 值等功能[^3]。 #### 使用说明 1. **初始化**:创建 `LinearBasis` 对象来存储线性基。 2. **插入元素**:调用 `insert(x)` 方法将新的整数 \( x \) 添加至线性基中。 3. **判断存在性**:使用 `contains(x)` 来验证某一值是否可以通过现有线性基中的元素异或得到。 4. **求最大 XOR 值**:调用 `max_xor()` 获取当前线性基所能产生的最大 XOR 结果。 5. **枚举所有可能值**:利用 `get_all_elements()` 返回线性基所覆盖的所有可能值列表。 此实现适用于大数涉及二进制运算的问题场景,并具有较高的效率和灵活性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值