字典树处理《异或》

来源:互联网 发布:2016年餐饮行业数据 编辑:程序博客网 时间:2024/06/05 00:31

题目:
问题很简单,现在有一个数组a1,a2,a3……an。你的任务就是找到一个连续子段[l,r],使得al^al+1^……^ar达到最大。
Input
多组输入,每组有两行。第一行有一个整数n(1<=n<=10^5),表示数组的元素个数。第二行有n个元素,依次表示数组的元素。(0<=ai<=10^6)
Output
每组输出一行,这行仅一个数字。表示最大的连续子段异或值。
Sample Input
Raw
5
1 2 3 4 5
5
2 3 2 3
      初次接触字典树,看了很多大神的代码,因为我根本不知道为什么字典树可以处理异或,现在有了一点点理解所以写一下博客强化一下记忆。
题目分析
       首先要明白异或是什么,异或就是相对于二进制的一种运算,相同为0,不同为1;
       对于这道题我们先处理一个前缀,即1~2,1~3,~~~~,1~n,的异或值;对于l~~r区间的异或值就为1~~r的异或值在异或1~~l-1的异或值;现在这个问题就变成了在前缀数组里找两个数求他们异或值得 最大;
       因为每一位只有0,1,两种状态,所以就像一个二叉,我们题目的数据范围为10^4所以25位就可以了,我们先建立一个字典树,当我们对字典树进行访问时就对答案进行比较看谁最大,我们从最高位进行判断,如果最高位有不同(相同1,不同0)的那么这个答案肯定是最优的,我们再进行判断下一位,如果最高位相同我们就直接判断下一位,又看看下一位是否相同,或者不同,下面代码判断相同不同我用的bool类型如果有不同的话,我肯定是建立了节点的 如果相同就找不到!k这个节点。
       废话多都说了,上码。
AC代码

#include <iostream>#include <stdio.h>#include <string.h>using namespace std;int a[100005];int tree[1000005][2];int clk=0;void add(int qq){    int i,len=25,rt=0;    bool k;    for (i=len;i>=0;i--)    {        k=qq&(1<<i);        if(!tree[rt][k])            tree[rt][k]=++clk;        rt=tree[rt][k];    }}int que(int qq){    int rt=0,len=25,i;    int an=0;    bool k;    for (i=len;i>=0;i--)    {        k=qq&(1<<i);        if(tree[rt][!k])        {            an=an+(1<<i);            rt=tree[rt][!k];        }        else            rt=tree[rt][k];    }    return an;}int main (){    int n,i,k;    while (scanf ("%d",&n)!=EOF)    {        memset(tree,0,sizeof(tree));        clk=0; int ans=0;        scanf ("%d",&a[0]);        for (i=1;i<n;i++)        {            scanf ("%d",&k);            a[i]=k^a[i-1];        }        add(0);        for (i=0;i<n;i++)        {            add(a[i]);            int maxn=que(a[i]);            ans=max(ans,maxn);        }        printf ("%d\n",ans);    }    return 0;}
0 0
原创粉丝点击