专栏文章

P13895 题解

P13895题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minzoymj
此快照首次捕获于
2025/12/02 10:59
3 个月前
此快照最后确认于
2025/12/02 10:59
3 个月前
查看原文
看到“选择两个不相交的子段”,想到经典 trick:两边分开做,最后统计答案。
假设我们知道了对于任意一个 ii1i1\sim i(称其为左边)和 i+1ni+1\sim n(称其为右边)的子段分别的最大异或和、最小异或和,我们直接枚举 ii,然后答案就是左边的最大值减右边最小值,右边的最大值减左边最小值中的 max。
CPP
rep(i, 1, n - 1)
{
	int s1 = maxl[i] - minr[i + 1];
	int s2 = maxr[i + 1] - minl[i];
	//minl, maxl, minr, maxr 分别表示两边的最小最大异或和
	ans = max(ans, max(s1, s2));
}
考虑如何求这四个数组。
我们先求左边的情况,右边的情况可以类比。
ssaa 的前缀异或和数组,我们注意到 i=lrai=srsl1\oplus_{i = l}^{r} a_i=s_r\oplus s_{l - 1}
于是我们就把一段区间的异或和转化为了两个数的异或的值。
我们枚举右端点 rr,然后找一个 ll 使得 srsl1s_r\oplus s_{l - 1} 最大(或者最小),可以用 01-trie 解决。
注意这样可以计算到所有区间,右边的情况类比就行了。
CPP
cin >> n;
r(n) cin >> a[i], la[i] = la[i - 1] ^ a[i]; 
reb(i, n, 1) ra[i] = ra[i + 1] ^ a[i];
maxl[0] = maxr[n + 1] = 0;
minl[0] = minr[n + 1] = INT_MAX;
tl.insert(0), tr.insert(0);
r(n) // 枚举右端点 i
{
	int k1 = tl.findmx(la[i]);
	int k2 = tl.findmn(la[i]);
	tl.insert(la[i]);
	maxl[i] = max(maxl[i - 1], k1);
	minl[i] = min(minl[i - 1], k2);
}
reb(i, n, 1)
{
	int k1 = tr.findmx(ra[i]);
	int k2 = tr.findmn(ra[i]);
	tr.insert(ra[i]);
	maxr[i] = max(maxr[i + 1], k1);
	minr[i] = min(minr[i + 1], k2);
}
01-trie 封装代码CPP
struct Trie
{
	int tr[N << 3][2], cnt = 0;
	void insert(int x)
	{
		int p = 0;
		reb(i, 20, 0)
		{
			bool vl = x & (1 << i);
			if (!tr[p][vl])
				tr[p][vl] = ++cnt;
			p = tr[p][vl];
		}
	}
	int findmx(int x)
	{
		int p = 0, res = 0;
		reb(i, 20, 0)
		{
			bool vl = x & (1 << i);
			if (tr[p][vl ^ 1])
				p = tr[p][vl ^ 1], res |= (1 << i);
			else p = tr[p][vl];
		}
		return res;
	}
	int findmn(int x)
	{
		int p = 0, res = 0;
		reb(i, 20, 0)
		{
			bool vl = x & (1 << i);
			if (tr[p][vl])
				p = tr[p][vl];
			else p = tr[p][vl ^ 1], res |= (1 << i);
		}
		return res;
	}
} tl, tr;
完整 AC 代码CPP
#include<bits/stdc++.h>
// #define int long long
#define r(x) for (int i = 1; i <= x; i++)
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reb(i, a, b) for (int i = a; i >= b; i--)
using namespace std;

const int N = 2e6 + 50;
int n, q, x, a[N], ans, maxl[N], maxr[N];
int la[N], ra[N], k, minl[N], minr[N];

struct Trie
{
	int tr[N << 3][2], cnt = 0;
	void insert(int x)
	{
		int p = 0;
		reb(i, 20, 0)
		{
			bool vl = x & (1 << i);
			if (!tr[p][vl])
				tr[p][vl] = ++cnt;
			p = tr[p][vl];
		}
	}
	int findmx(int x)
	{
		int p = 0, res = 0;
		reb(i, 20, 0)
		{
			bool vl = x & (1 << i);
			if (tr[p][vl ^ 1])
				p = tr[p][vl ^ 1], res |= (1 << i);
			else p = tr[p][vl];
		}
		return res;
	}
	int findmn(int x)
	{
		int p = 0, res = 0;
		reb(i, 20, 0)
		{
			bool vl = x & (1 << i);
			if (tr[p][vl])
				p = tr[p][vl];
			else p = tr[p][vl ^ 1], res |= (1 << i);
		}
		return res;
	}
} tl, tr;

signed main()
{
	cin.tie(0)->sync_with_stdio(0);
	cin >> n;
	r(n) cin >> a[i], la[i] = la[i - 1] ^ a[i]; 
	reb(i, n, 1) ra[i] = ra[i + 1] ^ a[i];
	maxl[0] = maxr[n + 1] = 0;
	minl[0] = minr[n + 1] = INT_MAX;
	tl.insert(0), tr.insert(0);
	r(n)
	{
		int k1 = tl.findmx(la[i]);
		int k2 = tl.findmn(la[i]);
		tl.insert(la[i]);
		maxl[i] = max(maxl[i - 1], k1);
		minl[i] = min(minl[i - 1], k2);
	}
	reb(i, n, 1)
	{
		int k1 = tr.findmx(ra[i]);
		int k2 = tr.findmn(ra[i]);
		tr.insert(ra[i]);
		maxr[i] = max(maxr[i + 1], k1);
		minr[i] = min(minr[i + 1], k2);
	}
	rep(i, 1, n - 1)
	{
		int s1 = maxl[i] - minr[i + 1];
		int s2 = maxr[i + 1] - minl[i];
		ans = max(ans, max(s1, s2));
	}
	cout << ans << "\n";
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...