LOJ 一本通提高篇2.3Trie字典树 例题+练习(坑)

复习时食用,会比较简略。

原理就不讲了,还不会字典树的先下车吧。


目录

#10049. 「一本通 2.3 例 1」Phone List

#10050. 「一本通 2.3 例 2」The XOR Largest Pair

#10051. 「一本通 2.3 例 3」Nikitosh 和异或

#10052. 「一本通 2.3 练习 1」Immediate Decodability

#10053. 「一本通 2.3 练习 2」L 语言

#10054. 「一本通 2.3 练习 3」Secret Message 秘密信息

#2012. 「SCOI2016」背单词

#10056. 「一本通 2.3 练习 5」The XOR-longest Path


#10049. 「一本通 2.3 例 1」Phone List

 

#10050. 「一本通 2.3 例 2」The XOR Largest Pair

题目

题目大意

在给定的N个整数中选出两个进行异或运算。

得到的结果最大是多少?

对于100%的数据,1<=n<=10^5,0<=ai<2^31。

题目分析

百度科普:异或即两个输入相同时为0,不同则为1。

首首先化成二进制建树。

为了让异或值max当然是要01反着跑,即一边跑向1另一边跑向0

化为二进制后第i位不同则:ans+=2^(i-1)。

每插入一个数就跑一遍,要么你建完树再跑也行。

建树从高位到低位。废话肯定先捡大便宜再捡小便宜。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,len=0;
long long a[100010],ans=0,biao=1;
struct node{int son[10];}tr[3100010];

void bt(long long aa)
{
	int now=0,x,d=0,k[40];
	long long kkk=biao,aans=0;
	for(int i=1;i<=32;i++)
	{
		if(aa>=kkk) x=1,aa-=kkk;
		else x=0;
		if(tr[now].son[x]==0)
		{
			len++,tr[now].son[x]=len,now=len;
			tr[now].son[0]=tr[now].son[1]=0;
		}
		else now=tr[now].son[x];
		d++; k[d]=x;//k存这个数化为二进制每一位上的数 
		kkk/=2;
	}
	now=0; kkk=biao;
	for(int i=1;i<=32;i++)
	{
		//是1往0跑,是0往1跑 
		if(tr[now].son[1-k[i]]!=0) 
		{
			aans+=kkk;
			now=tr[now].son[1-k[i]];
		}
		else now=tr[now].son[k[i]];//条件不允许你乱跑 
		kkk/=2;
	}
	ans=max(ans,aans);
}

int main()
{
	scanf("%d",&n);
	tr[0].son[0]=tr[0].son[1]=0;
	for(int i=1;i<=31;i++) biao*=2;
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		bt(a[i]);
	}
	printf("%lld",ans);
	return 0;
}

 

#10051. 「一本通 2.3 例 3」Nikitosh 和异或

题目

题目大意

给定一个含N个元素的数组A,下标从1开始。

找出式子的最大值:(A[l_1]⨁A[l_1+1]⨁…⨁A[r_1])+(A[l_2]⨁A[l_2+1]⨁…⨁A[r_2])。

其中1≤l_1≤r_1<l_2≤r_2≤N,x⨁y表示x和y的按位异或。

对于100%的数据,2<=n<=4*10^5,0<=ai<=10^9。

题目分析

首先记录异或前缀和s[i]=a[1]⊕a[2]⊕a[3]...⊕a[i]。

设l[i]为以i结尾的区间中,异或值的最大值。

因为异或有x⊕x=0的性质,所以区间[l,r]的异或值

=a[l]⊕a[l+1]⊕...⊕a

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值