字符串训练之二
字符串训练****
例题二:
题目描述:
在一个有 N个元素的序列 A 中,找出 下面式子的最大值
(A[L1]A[L1+1]^^^^A[R1-1]A[R1])+(A[L2]A[L2+1]^^^^A[R2-1]A[R2])的最大值
且要满足:1<=L1<=R1<L2<=R2<=N,N<=4e5,Ai<=1e9;
分析:肯定看到这题目描述想什么狗屁字符串,应该乱搞可以过の
但当你仔细想想乱搞是搞不出来的.....emmm
首先肯定能够想到和前缀异或有关
又是一个最值问题????dp
然后发现式子中间是有断点的
假如知道了断点前的最大值****和断点后的最大值**
加起来O(n)线性扫一遍不就知道答案了吗?
即pre[i]+suf[i+1];
现在主要就是求pre[i],suf[i]同理
现在就要利用前面说的前缀异或了
设sum[i]=A[1]A[2]A[3]^^^^^^A[i];
pre[x]=max(sum[i]^sum[j])其中1<=i<=j<x
问题转化为
要求一个序列中[1,x]任意两个异或的最大值[板子题]
solution:
二进制拆分,放入一个Trie中,从最高位开始,每次选与它相反的(0--->1||1--->0),如果没得选就直接向下走
同理suf
code:
#include <iostream>
using namespace std;
int n,a[5000000],now,trie[50000000][3],tot,l[5000000],r[5000000],ans;
int insert(int x)
{
int u(0);
for (int i=30;i>=0;i--)
{
int ch=(x>>i)&1;
if (!trie[u][ch])trie[u][ch]=++tot;
u=trie[u][ch];
}
}
int query(int x)
{
int u(0),an(0);
for (int i=30;i>=0;i--)
{
int ch=(x>>i)&1;
if (trie[u][!ch])u=trie[u][!ch],an+=1<<i;
else u=trie[u][ch];
}
return an;
}
int clear()
{
for (int i=0;i<=tot;i++)
for (int j=0;j<=1;j++)
trie[i][j]=0;
tot=0;
now=0;
}
int main()
{
cin>>n;
insert(0);
for (int i=1;i<=n;i++)
cin>>a[i],now^=a[i],insert(now),l[i]=max(l[i-1],query(now));
clear();
insert(0);
for (int i=n;i>=1;i--)
now^=a[i],insert(now),r[i]=max(r[i+1],query(now));
for (int i=1;i<n;i++)
ans=max(ans,l[i]+r[i+1]);
cout<<ans<<endl;
return 0;
}