Description
对于一个长度为m的序列a,记 f ( a ) = max ( ( a 1 x o r . . . x o r a i ) + ( a i + 1 x o r . . . x o r a n ) ) , i ∈ [ 0 , m ] f(a)=\max((a_1\ xor\ ...\ xor\ a_i)+(a_{i+1}\ xor\ ...\ xor\ a_n)),i\in[0,m] f(a)=max((a1 xor ... xor ai)+(ai+1 xor ... xor an)),i∈[0,m]
给你一个长度为n的序列a,依次输出
a
[
1..1
]
,
a
[
1..2
]
,
.
.
.
,
a
[
1..
n
]
a[1..1],a[1..2],...,a[1..n]
a[1..1],a[1..2],...,a[1..n]的f值
a
i
≤
1
0
6
,
n
≤
300000
a_i\leq 10^6,n\leq 300000
ai≤106,n≤300000
Solution
我们先将序列a做一次前缀异或,记
b
i
=
a
1
x
o
r
.
.
.
x
o
r
a
i
b_i=a_1\ xor\ ...\ xor\ a_i
bi=a1 xor ... xor ai
那么
f
(
a
[
1..
i
]
)
=
max
(
b
j
+
(
b
i
x
o
r
b
j
)
)
,
j
∈
[
0
,
i
]
f(a[1..i])=\max(b_j+(b_i\ xor\ b_j)),j\in[0,i]
f(a[1..i])=max(bj+(bi xor bj)),j∈[0,i]
从高到低考虑
b
i
b_i
bi的二进制位,如果
2
k
2^k
2k这一位为1,那么j无论怎么选这一位对总和贡献都是
2
k
2^k
2k
如果这一位为0,那么就要看
b
j
b_j
bj的这一位,如果为1那么就有
2
k
+
1
2^{k+1}
2k+1的贡献,否则贡献就是0
问题就转化成我们需要选择一个j,使得 b j b_j bj在 b i b_i bi为0的更的高位要尽可能为1,为1的位可以任意,然后按位确定答案。
问题就在于这个为1的位可以任意。我们很难用一个Trie来维护,因为碰到1需要两边都一起跑。
考虑预处理
预处理状态
F
[
S
]
F[S]
F[S],S为一个二进制状态,一开始S的意义就是S这个二进制数在序列中最早出现的位置,直接扫一遍存进来即可。
为了满足我们为1的位可以任意取,我们修改
F
[
S
]
F[S]
F[S]的定义,
F
[
S
]
F[S]
F[S]表示所有二进制数
T
T
T在序列中最早出现的位置,
S
a
n
d
T
=
S
S\ and\ T=S
S and T=S,或者说
S
∈
T
S\in T
S∈T,即S的某一位为0实际上T可以为0或1。
这个动态维护比较难,我们先扫一遍存进来,然后做DP,枚举每一个为0的位转移。
本质上,这是一个高维前缀和的过程。
现在查询答案就好查了,我们从高位到低位扫 b i b_i bi,前面已经确定好的不变,然后看这一位是0还是1,是0就判断是否存在 F [ S ′ ] ≤ i , F[S']\leq i, F[S′]≤i,S’前面都满足且这一位为1,然后直接统计即可。
(其实用Trie也是可以的,我们先离线将Trie建出来,然后1的儿子不变,0的儿子合并1的儿子状态,本质与上面相同)
复杂度 O ( ( n + max ( a ) ) log max ( a ) ) O((n+\max(a))\log \max(a)) O((n+max(a))logmax(a))
Code
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 460005
using namespace std;
int a[N],n,f[1048576],cf[21],ans[N];
int main()
{
cin>>n;
a[0]=0;
cf[0]=1;
fo(i,1,20) cf[i]=cf[i-1]<<1;
memset(f,107,sizeof(f));
fo(i,1,n)
{
scanf("%d",&a[i]),a[i]^=a[i-1];
f[a[i]]=min(f[a[i]],i);
}
fod(j,cf[20]-1,0)
fo(i,0,19) if(!(j&cf[i])) f[j]=min(f[j],f[j^cf[i]]);
fo(i,1,n)
{
int s=0,v=0;
fod(j,19,0)
{
if(a[i]&cf[j]) s+=cf[j];
else
{
v^=cf[j];
if(f[v]<=i) s+=cf[j+1];
else v^=cf[j];
}
}
printf("%d\n",s);
}
}