复习时食用,会比较简略。
原理就不讲了,还不会字典树的先下车吧。
目录
#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
题目
在给定的N个整数中选出两个进行异或运算。
得到的结果最大是多少?
对于100%的数据,1<=n<=10^5,0<=ai<2^31。
百度科普:异或即两个输入相同时为0,不同则为1。
首首先化成二进制建树。
为了让异或值max当然是要01反着跑,即一边跑向1另一边跑向0。
化为二进制后第i位不同则:ans+=2^(i-1)。
每插入一个数就跑一遍,要么你建完树再跑也行。
建树从高位到低位。废话肯定先捡大便宜再捡小便宜。
#include
#include
#include
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;
}
题目
给定一个含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 对于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[r] =(a[1]⊕a[2]⊕a[3]...⊕a[l−1])⊕(a[1]⊕a[2]⊕a[3]...⊕a[r]) =s[l−1]⊕s[r] 所以求l[i],转化为找j
以上引自:https://www.cnblogs.com/qwerta/p/9822368.html l_1和r_1正着找,得出前半段得max值。 l_2和r_2反正再找一遍,得出后半段得max值。道理等同于以上。即 首先记录异或前缀和s[i]=a[n]⊕a[n-1]⊕a[n-2]...⊕a[1]。 设l[i]为以i开头的区间中,异或值的最大值。 因为异或有x⊕x=0的性质,所以区间[l,r]的异或值 =a[l]⊕a[l+1]⊕...⊕a[r] =(a[l]⊕a[l+1]⊕a[l+2]...⊕a[n])⊕(a[r+1]⊕a[r+2]⊕a[r+3]...⊕a[n]) =s[l]⊕s[r+1] 应该没有毛病吧... 注意不管正着找还是反着找都要先放一个数——0进去。为什么? 正着放时则表示从第1位到第i位,反着放时则表示从第i位到第n位。 这个应该不难懂? 从上文可以知道正着找:区间[l,r]的异或值=s[l−1]⊕s[r] 那么当l==1时,即为s[0]⊕s[r]。s[0]就是0啦。 给出若干数字串,判断是否有一个数字串是另一个串的前缀。 数字串只包含0,1,记每个数字串长度为l,则1<=l<=10。每组数据至少有2个数字串,至多有8个数字串。 跟#10049. 「一本通 2.3 例 1」Phone List 题目 我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部分,且每一个部分都是字典D中的单词。 给定一个字典D,你需要判断若干段文章在字典D下是否能够被理解。 并给出其在字典D下能够被理解的最长前缀的位置。 好吧,字典树+暴力 代码好懂? 一些解释放代码里了。 我太菜了还不会,留坑。 题目 给定一棵n个点的带权树,求树上最长的异或和路径。 对于100%的数据,1<=n<=10^5,1<=u,v,<=n,0<=w<2^31。 甚妙。我努力解释一下。 根据每个结点到根结点的异或值建一棵字典树。 在字典树上努力向两边跑。道理同理于#10050. 「一本通 2.3 例 2」The XOR Largest Pair 从而得出最大答案。 同理#10050. 「一本通 2.3 例 2」The XOR Largest Pair,你可以每插入一个数就跑一遍,建完树再跑也行。 那么问题来了,为什么可以这样做??? 无非两种情况 1、两个数在根节点的同侧。 举个例子:1为根节点,2为1的儿子,3为2的儿子(一条链)。那么我们事先处理好了1到2的异或值和1到3的异或值。(敲黑板重点来了!!!)我们可以直接异或1到2的异或值和1到3的异或值然后得到2到3的异或值。因为异或有x⊕x=0的性质。所以任意两个在根节点同侧的点可以得到异或值。 2、两个数在根节点的异侧。 再举个例子:1为根节点,2为1的第一个儿子,3为1的第二个儿子(他好像并没有保证是二叉树)。那么2到3的异或值显然能表示为1到2的异或值 异或 1到3的异或值。 所以一切好像都没什么毛病。 注意!每个数到根节点的异或值也可以作为答案。 那么,以上。 题目分析
代码有点奇怪??? %%%
我觉得解释得海星???我的语文水平也就这样了。代码
#include
#10052. 「一本通 2.3 练习 1」Immediate Decodability
题目大意
题目分析
一模一样...不过换了个皮囊。代码
#include
#10053. 「一本通 2.3 练习 2」L 语言
题目大意
题目分析
一眼AC自动机?听我的不要慌。不用AC自动机我我我能做!(最喜欢暴力了...滑稽)不管不管反正我觉得好懂。代码
#include
#10054. 「一本通 2.3 练习 3」Secret Message 秘密信息
#2012. 「SCOI2016」背单词
猛然惊觉我好多坑没填。#10056. 「一本通 2.3 练习 5」The XOR-longest Path
题目大意
题目分析
代码
#include