Codechef REBXOR HYSBZ - 4260(01字典树+区间异或最大)

本文介绍了一种求解两个不相交区间异或和最大值的问题,通过使用前缀和与01字典树结合的方法,实现了高效求解。文章详细解释了算法思路,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
Input
输入数据的第一行包含一个整数N,表示数组中的元素个数。
第二行包含N个整数A1,A2,…,AN。
Output
输出一行包含给定表达式可能的最大值。
Sample Input
5
1 2 3 1 2
Sample Output
6
Hint
满足条件的(l1,r1,l2,r2)有:(1,2,3,3),(1,2,4,5),(3,3,4,5)。

对于100%的数据,2 ≤ N ≤ 4*105,0 ≤ Ai ≤ 109。
做了几个求区间异或最大的题目。求区间异或最大就是求个前缀,然后就是普通的01字典树了。
就像这个题目,求两个不相交的区间,然后两个区间的异或和最大。
我们想求一个前缀区间异或最大值并且记录下来存到数组中,然后再去枚举后缀的区间,再去更新最大值。
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#define ll long long
using namespace std;

const int maxx=4e5+100;
struct node{
	int trie[2];
	int num;
}p[maxx*33];
int sum[maxx],pre[maxx];
int a[maxx],dp[maxx];
int n,tot;

inline void Insert(int x)
{
	int root=0;
	int id;
	for(int i=32;i>=0;i--)
	{
		id=(x>>i)&1;
		if(!p[root].trie[id]) p[root].trie[id]=++tot;
		root=p[root].trie[id];
	}
	p[root].num=x;
}
inline int Find(int x)
{
	int root=0;
	int id;
	for(int i=32;i>=0;i--)
	{
		id=(x>>i)&1;
		if(p[root].trie[id^1]) root=p[root].trie[id^1];
		else root=p[root].trie[id];
	}
	return p[root].num^x;
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		tot=0;
		for(int i=1;i<=n;i++) scanf("%d",&a[i]);
		for(int i=1;i<=n;i++) sum[i]=sum[i-1]^a[i];//前缀
		for(int i=n;i>=1;i--) pre[i]=pre[i+1]^a[i];//后缀
		Insert(0);
		for(int i=1;i<=n;i++)
		{
			dp[i]=max(dp[i-1],Find(sum[i]));
			Insert(sum[i]);
		}
		int _max=0;
		for(int i=n;i>=1;i--)
		{
			_max=max(_max,Find(pre[i])+dp[i-1]);//枚举后缀区间异或最大值再加上前面求过的前缀,他们的和去更新最大值
			Insert(pre[i]);
		}
		printf("%d\n",_max);
	}
	return 0;
}

努力加油a啊,(o)/~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值