线性基例题

例题1

【模板】线性基 - 洛谷

考察最大值查询

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int mo = 1e3;
const int N = 2e5 + 5;
ll d[70];
void add(ll x)
{
	for (int i = 50; i >= 0; i--)
	{
		if (x & (1ll << i)) //注意,如果i大于31,前面的1的后面一定要加ll
		{
			if (d[i])x ^= d[i];
			else
			{
				d[i] = x;
				break;//插入成功就退出
			}
		}
	}
}
ll ans()
{
	ll anss = 0;
	for (int i = 50; i >= 0; i--) //记得从线性基的最高位开始
		if ((anss ^ d[i]) > anss)anss ^= d[i];
	return anss;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n, x;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> x;
		add(x);
	}
	cout << ans();
	return 0;
}

例题2

考察存在情况的判断

xor序列

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int mo = 1e3;
const int N = 2e5 + 5;
ll b[70], d[70];
void add(ll x)
{
	for (int i = 60; i >= 0; i--)
	{
		if (x & (1ll << i)) //注意,如果i大于31,前面的1的后面一定要加ll
		{
			if (d[i])x ^= d[i];
			else
			{
				d[i] = x;
				break;//插入成功就退出
			}
		}
	}
}
bool query(int y)
{
	for (int i = 60; i >= 0; i--)
	{
		if (y & (1ll << i)) //注意,如果i大于31,前面的1的后面一定要加ll
		{
			if (b[i])y ^= b[i];
			else
			{
				b[i] = y;
				return 0;
			}
		}
	}
	return 1;
}
ll ans()
{
	ll anss = 0;
	for (int i = 50; i >= 0; i--) //记得从线性基的最高位开始
		if ((anss ^ d[i]) > anss)anss ^= d[i];
	return anss;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n, x, y;
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> x;
		add(x);
	}
	int q;
	cin >> q;
	while (q--)
	{
		memcpy(b,d,sizeof d);
		cin >> x >> y;
		y^=x;
		if (query(y))
		{
			cout << "YES\n";
		}
		else
		{
			cout << "NO\n";
		}
	}
	return 0;
}

例题三 


[TJOI2008]彩灯 - 洛谷

我们把开关看成原数列,而灯的开闭就是其二进制分解的结果,两个或者若干个开关异或的结果就是最终灯的开闭情况,用线性基表示全部结果,

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int mo = 2008;
const int N = 2e5 + 5;
ll b[70], d[70];
void add(ll x)
{
	for (int i = 60; i >= 0; i--)
	{
		if (x & (1ll << i)) //注意,如果i大于31,前面的1的后面一定要加ll
		{
			if (d[i])x ^= d[i];
			else
			{
				d[i] = x;
				break;//插入成功就退出
			}
		}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n, m, x;
	cin >> n >> m;
	char c;
	while (m--)
	{
		x=0;
		for (int i = 0; i < n; i++)
		{
			cin >> c;
			if (c == 'O')
			{
				x|=1ll<<i;
			}
		}
		add(x);
	}
	ll ans=1;
	for(int i=0;i<=60;i++)
	{
		if(d[i]!=0)
		{
			ans<<=1;
			ans%=mo;
		}
	}
	cout<<ans;
	return 0;
}

例题4

牛客(Zero XOR Subset)-less

cf(Zero XOR Subset)-less

考察性质2,3. 根据题意,我们发现一个异或子段可以是前缀异或数组相异或得到的,所以线性基可以记载全部n个异或前缀数组的异或情况,性质2保证了它们不可能存在异或结果是0的情况,性质3保证了这些子段的异或值都能够被表示。而值得注意的是,如果全部n个数异或之后不为0,那么我们线性基一定能够将这n个数都囊括进去,再利用这个大的前缀异或值去“分解”剩余小的。可如果n个数异或之后是0,那么至少这一结果不满足线性基表示非零的性质,从而无法被加入,无法参与切割,最右端点也不再是n

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const int mo = 2008;
const int N = 2e5 + 5;
ll a[N], d[70];
void add(ll x)
{
	for (int i = 60; i >= 0; i--)
	{
		if (x & (1ll << i)) //注意,如果i大于31,前面的1的后面一定要加ll
		{
			if (d[i])x ^= d[i];
			else
			{
				d[i] = x;
				break;//插入成功就退出
			}
		}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	ll n, now=0;
	cin >> n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		now^=a[i];
		add(now); 
	}
	
	if(now==0)
	{
		cout<<-1;
		return 0;
	}
	
	ll ans=0;
	for(int i=0;i<=60;i++)
	{
		if(d[i]!=0)
		{
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

### 使用单纯形法解决线性规划问的示例 #### 示例题目 考虑如下线性规划问: 最大化 \( Z = 3x_1 + 5x_2 \) 受制于: \[ \begin{align*} x_1 & \leq 4 \\ 2x_2 & \leq 12 \\ 3x_1 + 2x_2 & \leq 18 \\ x_1, x_2 & \geq 0 \end{align*} \] 引入松弛变量 \( x_3, x_4, x_5 \),使得不等式变为等式形式。 初始模型可以表示为: \[ \begin{align*} Z &= 3x_1 + 5x_2 + 0x_3 + 0x_4 + 0x_5 \\ s.t.\quad x_1 + x_3 &= 4 \\ 2x_2 + x_4 &= 12 \\ 3x_1 + 2x_2 + x_5 &= 18 \\ x_i & \geq 0,\ i=1,2,...,5 \end{align*} \] #### 初始单纯形表 | 基 | \( b \) | \( x_1 \) | \( x_2 \) | \( x_3 \) | \( x_4 \) | \( x_5 \) | |--|-----------|-----------|-----------|-----------| | \( x_3 \) | 4 | 1 | 0 | 1 | 0 | 0 | | \( x_4 \) | 12 | 0 | 2 | 0 | 1 | 0 | | \( x_5 \) | 18 | 3 | 2 | 0 | 0 | 1 | | \( z_j-c_j \)| 0 |-3 |-5 | 0 | 0 | 0 | 由于存在负检验数,继续迭代直到所有检验数非负为止[^1]。 #### 第一次迭代 选取最大负检验数对应的列作为入基变量(\( x_2 \)),并计算最小比值确定离基变量(\( x_4 \))。更新后的表格如下所示: | 基 | \( b \) | \( x_1 \) | \( x_2 \) | \( x_3 \) | \( x_4 \) | \( x_5 \) | |-------|---------|-----------|-----------|-----------|-----------|-----------| | \( x_3 \) | 4 | 1 | 0 | 1 | 0 | 0 | | \( x_2 \) | 6 | 0 | 1 | 0 | 0.5 | 0 | | \( x_5 \) | 6 | 3 | 0 | 0 | -1 | 1 | | \( z_j-c_j \) | 30 | -3 | 0 | 0 | 2.5 | 0 | 再次检查检验数,发现仍有一个负值,因此需进一步迭代[^2]。 #### 第二次迭代 这次选择 \( x_1 \) 作为新的入基变量,并通过最小比值得到 \( x_3 \) 将被替换。最终得到最优解: | 基 | \( b \) | \( x_1 \) | \( x_2 \) | \( x_3 \) | \( x_4 \) | \( x_5 \) | |--|-----------|-----------|-----------| | \( x_1 \) | 4/3 | 1 | 0 | 1/3 | 0 | 0 | | \( x_2 \) | 6 | 0 | 1 | 0 | 0.5 | 0 | | \( x_5 \) | 2 | 0 | 0 | -1 | -1 | 1 | | \( z_j-c_j \) | 38 | 0 | 0 | 1 | 2.5 | 0 | 此时所有的检验数均为正,表明已经找到了最优解:\( (x_1,x_2)=(4/3,6)\), 对应的目标函数值为 \( Z_{max}=38 \).
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值