【UR #22】月球列车
【UR #22】月球列车
下文中,\(x\) 的第 \(i\) 位是指 \(x\) 对应二进制中 \(2^i\) 的系数。
同理,\(x\) 的前 \(i\) 位是指 \(x\) 对应二进制中第 \(0,1,\dots,i\) 位合在一起的结果。
考虑求出 \(a_i + x\) 的第 \(j\) 位,其为以下三个值的异或:
-
\(a_i\) 的第 \(j\) 位
-
\(x\) 的第 \(j\) 位
-
\(a_i\) 的前 \(j-1\) 位与 \(x\) 的前 \(j-1\) 位相加是否进位。
前两部分可以在最后算答案的时候异或上去,主要问题是第三部分。
我们令 \(b_{j,i} = a_i \land (2^j - 1)\),即 \(a_i\) 的前 \(j-1\) 位。
后者要求 \(b_{j,i} + x \land (2^j - 1) \geq 2^j\)。
我们稍作转化,即 \(b_{j,i} \geq 2^j - x \land (2^j - 1)\)。
考虑对 \(b_j\) 排序,此时我们在 \(b_j\) 中二分 \(2^j - x \land (2^j - 1)\) 即可。
此时我们得到了 \(O(n \log n \log V)\) 的做法,考虑优化。
首先是预处理 \(b_j\) 部分,我们只需要获得 \(b_j\) 排序后的结果。
\(b_j\) 是在 \(b_{j-1}\) 的基础上添加最高位得到的,考虑将 \(0\) 移到 \(1\) 的前面。
只要不改变相对顺序,这个算法就是正确的,可以做到 \(O(n \log n)\) 预处理。
接下来考虑查询部分,我们仍然考虑观察 \(2^j - x \land (2^j - 1)\) 的性质。
我们举几个不同的例子。
\(x=101001\) 对应 \(000001,000001,000011,000111,000111,010111\)。
\(x=101100\) 对应 \(000001,000010,000100,000100,000100,010100\)。
也就是说,在 \(\text{lowbit}\) 之前,询问的数一直是 \(2^j\),可以预处理。
事实上我们并不需要预处理,因为此时 \(a_j\) 的前 \(j-1\) 位加上 \(0\) 不可能进位。
接下来在 \(\text{lowbit}\) 之后,每次询问的数是在前一个数上加一位形成的。
这个过程可以 \(O(1)\) 转移,于是我们得到了 \(O(n \log V)\) 的复杂度。
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int C=61;
int n,m,t;
long long a[250010],b[C][250010],to_pos_0[C][250010],to_pos_1[C][250010],xor_sum;
void init(){
for(int i=1;i<=n;i++){
xor_sum^=a[i];
}
for(int i=1;i<=n;i++){
b[0][i]=i;
}
for(int j=1;j<C;j++){
for(int i=1;i<=n;i++){
if(a[b[j-1][i]]&(1ll<<(j-1))){
to_pos_0[j-1][0]++;
}
}
for(int i=1;i<=n;i++){
if(!(a[b[j-1][i]]&(1ll<<(j-1)))){
to_pos_0[j-1][i]=to_pos_0[j-1][i-1]+1;
to_pos_1[j-1][i]=to_pos_1[j-1][i-1];
b[j][to_pos_0[j-1][i]]=b[j-1][i];
}
else{
to_pos_0[j-1][i]=to_pos_0[j-1][i-1];
to_pos_1[j-1][i]=to_pos_1[j-1][i-1]+1;
b[j][to_pos_1[j-1][i]]=b[j-1][i];
}
}
}
}
long long calc(long long num){
long long ans=xor_sum;
if(n&1){
ans^=num;
}
int pre_pos=n;
long long lowbit=num&-num;
num^=lowbit;
for(int i=0;i<C;i++){
if((1ll<<i)>lowbit){
if(!(num&(1ll<<(i-1)))){
pre_pos=to_pos_1[i-1][pre_pos];
}
else{
pre_pos=to_pos_0[i-1][pre_pos];
}
if(pre_pos&1){
ans^=1ll<<i;
}
}
}
return ans;
}
int main(){
scanf("%d %d %d",&n,&m,&t);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
init();
long long last_ans=0;
while(m--){
long long v;
scanf("%lld",&v);
if(t){
v^=last_ans>>20;
}
last_ans=calc(v);
printf("%lld\n",last_ans);
}
return 0;
}

浙公网安备 33010602011771号