CF2064D 题解
chenxi2009 · · 题解
思路
考虑先按位分讨,手玩
类比一下,把这个
所以考虑按位从高位到低位、从右往左跳,对于
建议结合代码理解,时间复杂度
看官解学到一个函数 __lg(x),可以取出
代码
#include<bits/stdc++.h>
using namespace std;
int T,n,q,w[300000],s[300000],x,pre[300000][32],mxb,now,nxt;
int main(){
scanf("%d",&T);
while(T --){
scanf("%d%d",&n,&q);
for(int i = 1;i <= n;i ++) scanf("%d",&w[i]);
for(int i = 1;i <= n;i ++) s[i] = s[i - 1] ^ w[i];
for(int i = 1;i <= n;i ++){//pre_{i,j} 记录 w_{1,2,3,...,i} 中最靠右的 w_i>2^j 的位置
for(int j = 0;j <= __lg(w[i]);j ++) pre[i][j] = i;
for(int j = __lg(w[i]) + 1;j < 31;j ++) pre[i][j] = pre[i - 1][j];
}
for(int i = 1;i <= q;i ++){
scanf("%d",&x);
now = n;//now 记录 x 现在面前还没吃掉的是哪一只史莱姆
for(int j = 30;~j;j --){
if(x < 1 << j) continue;//x 比这一位小,跳过
nxt = pre[now][j];
x ^= s[now] ^ s[nxt],now = nxt;//x 比这一位大,一路走吃掉 w_{nxt+1,...,now}
if(!now || w[now] > x) break;//如果吃完了或吃不掉 w_now 就结束
x ^= w[now --];//吃掉 w_now
}
printf("%d ",n - now);
}
printf("\n");
}
return 0;
}