前缀树实现最大异或子数组

问题描述

数组异或和的定义:把数组中所有的数异或起来得到的值。给定一个整型数组arr,其中可能有正、有负,有零,求其中子数组的最大异或和。

输入
4
3 -28 -29 2
输出
7
说明
{-28,-29}这个子数组的异或和为7,是所有子数组中最大的

思路

对于求子数组问题,通常采取动态规划dp[i]=k表示前i项的异或值
那么对于其中的【i=>j】其异或值为dp[j]与dp[i-1]的“异或值做除法"

本题思路是维护一个前缀数组,即字典树形式
计算XOR[]表示前i项的异或值,那么对于以第i项结尾的子数组
其最大的异或值,应当在[1=>i] [2=>i]…等子数组中寻找
通过沿着前缀树,按照贪心的策略:
对于符号位,希望其与当前XOR[i]符号位一致(使得符号位为0 正数)
对于非符号位,希望其与当前XOR[i]的对应位置取反(使得中间位为1)

代码实现

#include<iostream>
#include<vector>
using namespace std;
struct node
{
    node* num[2];
};

node* head;
void add(int num)
{
    node* now=head;
    for(int i=31;i>=0;i--)
    {
        int t=1&(num>>i);//取num得第i位
        if(now->num[t]==NULL)
        {
            now->num[t]=new node{NULL,NULL};
            now=now->num[t];
        }
        else
            now=now->num[t];
    }
  
}
const int MAX=1e5+10;
int main()
{
    int n;
    cin>>n;
    int XOR[MAX]={0};
    for(int i=1;i<=n;i++)
    {
        int t;
        cin>>t;
        XOR[i]=XOR[i-1]^t;//前i项的异或值
    }
    head=new node{NULL,NULL};
    node* now=head;
    add(XOR[1]);
    int maxn=XOR[1];//第一项的异或值
    for(int i=2;i<=n;i++)
    {
        now=head;
        int ans=0;
        for(int j=31;j>=0;j--)
        {
            int t=1&(XOR[i]>>j);//取前i项异或值得第j位
            int target=!t;//希望值
            if(j==31) //符号位
            {
                target=t;
            }
            if(now->num[target]!=NULL) //存在这个数
            {
                now=now->num[target];
                ans=ans|((target^t)<<j);  //能够满足要求
            }
            else
            {
                now=now->num[!target];
                ans=ans|((!target^t)<<j);
            }
        }
        add(XOR[i]);
        maxn=max(maxn,ans);
    }
    cout<<maxn<<endl; 
}

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页