H - XOR 线性基

在这里插入图片描述在这里插入图片描述
利用期望的线性性,等价于计算每个数在集合中的方案数
线性基。先建立一个线性空间b,假设会的到r个基底,这r个基底是线性无关的(就是说,r个基底的数值无论怎么取,异或和都无法得到零),而剩下的n-r个数都可通过这r个基底之间异或得到。
要满足异或和等于0的话,就必须从n-r个数里面考虑。
对于这n-r个数,无论怎么取得到的异或和,在r个数中肯定有且只有一种组合方式使得这种组合方式的异或和等于n-r中取得的异或和。假设一个数必须在方案中,剩下的数有 2 n − r − 1 2^{n-r-1} 2nr1种取法,所以 a n s = n ∗ ( 2 n − r − 1 ) ans = n * (2^{n-r-1}) ans=n(2nr1)种取法。
对于r个基底,n-r个数中可能有可以代替它作为基底的数字。所以对构成r的数值枚举进行判断。(就类似于r个基底中的一个数跟n-r中的数换了一下,那么这个基底也有 2 n − r − 1 2^{n-r-1} 2nr1种方案数)。判断就是根据就是这个基底能不能由其他向量的线性组合出来。如果能就要加上 2 n − r − 1 2^{n-r-1} 2nr1种方案数。
所以每次都用n-r个数和r-1个其他基底构建线性空间,看看枚举的这个基底能否insert到线性空间中。
能就表示该数没有其他数与它线性相关,不能就表示可以由其他向量线性组合出来(就是可以跟n-r个数中的一个进行交换)。
下面是口胡,自己都不知道在说什么
进行枚举的时候枚举的是原来的数值而不是线性空间的基底数值。基底数值有点类似于正交分解后的基向量(比如这道题 2 ≤ 1 0 18 2\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);
	}
}
编码操作: 假设有一个长度为k的信息序列,我们要把它编码成长度为n的码字。首先,我们需要选择一个(n,k)线性分组码,该码可以由一个生成矩阵G来描述。G的大小为k×n,其中G的每一行都表示一个码字的组成部分(称为码字基)。 将信息序列乘以G,得到一个长度为n的码字。 Matlab代码实现: 假设我们选择了一个(7,4)线性分组码,生成矩阵G如下: G = [1 0 0 0 1 1 1; 0 1 0 0 0 1 1; 0 0 1 0 1 0 1; 0 0 0 1 1 1 0]; 然后,我们可以定义一个长度为k=4的信息序列m,如下: m = [1 0 1 1]; 接下来,我们可以将m乘以G,得到一个长度为n=7的码字c,如下: c = m*G c的值为[1 0 1 1 1 1 0]。 译码操作: 接收到一个长度为n的码字r,我们需要将其译码为一个长度为k的信息序列m。译码可以通过使用一个验矩阵H来实现,H的大小为(n-k)×n。H的每一行都表示一个验方程,它是码字基的线性组合,其和为0。 我们可以将r乘以H的转置,得到一个(n-k)×1的向量s。如果s的所有元素都为0,则r是一个有效的码字,我们可以将其译码为m。否则,我们需要找到一个错误的位置,并将其纠正。根据s的非零位置,我们可以计算出错误的位置,并翻转该位置上的比特,然后重新计算m。 Matlab代码实现: 假设我们接收到了一个长度为n=7的码字r,如下: r = [1 0 1 1 0 1 0]; 我们可以定义一个验矩阵H,如下: H = [1 1 0 1 1 0 0; 1 0 1 1 0 1 0; 0 1 1 1 0 0 1]; 将r乘以H的转置,得到一个3×1的向量s,如下: s = r*H' s的值为[1 1 1],表示有一个错误的比特。因为s的第1个元素是1,我们知道第1个码字基是错误的,所以我们需要翻转r的第1个比特,并重新计算m。 r(1) = mod(r(1)+1,2); 重新计算m: m = r(1:4) 现在,m的值为[0 0 1 1],与我们之前编码时使用的信息序列m相同。 误码率模拟: 我们可以使用Matlab中的通信工具箱来模拟误码率。首先,我们需要定义一个误码率向量,包括我们想要测试的不同误码率。然后,我们可以使用通信工具箱中的编码器和译码器来模拟传输,并计算误码率。 Matlab代码实现: 假设我们想要测试误码率为0.1、0.01和0.001的情况,我们可以定义一个误码率向量,如下: EbNoVec = [1 2 3]; berVec = zeros(size(EbNoVec)); 接下来,我们可以使用通信工具箱中的函数来定义编码器和译码器: enc = comm.LDPCEncoder; dec = comm.LDPCDecoder; 然后,我们可以使用通信工具箱中的函数来模拟传输,并计算误码率: for idx = 1:length(EbNoVec) % Set the noise figure based on the Eb/No noiseFig = 10^(-EbNoVec(idx)/20); % Create a random bit stream bits = randi([0 1], 1, 4); % Encode the bit stream encBits = enc(bits'); % Modulate the encoded bits modSig = pskmod(encBits, 2); % Add AWGN to the modulated signal rxSig = awgn(modSig, EbNoVec(idx), 'measured', 'dB'); % Demodulate the received signal demodSig = pskdemod(rxSig, 2); % Decode the demodulated signal decBits = dec(demodSig'); % Compare the decoded bits to the original bits errors = sum(xor(bits, decBits)); % Calculate the bit error rate berVec(idx) = errors/length(bits); end 最后,我们可以绘制误码率曲线: semilogy(EbNoVec, berVec) xlabel('Eb/No (dB)') ylabel('Bit Error Rate') grid on 这将显示误码率随信噪比的变化情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值