题意:
给出n个数,找到最短的区间异或和大于等于K 若没有则输出" - 1 "
思路:
首先我们维护出来异或前缀,我们知道[l~r]的异或前缀等于[ 1 ~ r ] ^ [1 ~ (l - 1) ]这个与前缀和有些相似。
然后我们用字典树维护出来这个前缀,通过记录节点的下表,写算出区间长度。
ll n,k,tot;
ll tree[maxn][2];
ll cnt[maxn];
ll a[maxn];
void insert(ll x,ll num){
ll pos=0,tmp;
for(int i=31;i>=0;i--){
tmp=x>>i &1;
if(!tree[pos][tmp]){
tree[pos][tmp] =++tot;
}
pos=tree[pos][tmp];
cnt[pos] = max(cnt[pos],num);
}
}
ll search(ll x){
ll top=0;
ll tmpx,tmpk;
ll l=0;
for(int i=31;i>=0;i--){
tmpx=x>>i&1;
tmpk=k>>i&1;
if(tmpx){///1
if(tmpk){///1
if(!tree[top][0]) return l;
top=tree[top][0];
}
else {
l=max(l,cnt[tree[top][0]]);
if(!tree[top][1])return l;
top=tree[top][1];
}
}else {
if(tmpk) {
if(!tree[top][1]) return l;
top=tree[top][1];
}else {
l=max(l,cnt[tree[top][1]]);
if(!tree[top][0]) return l;
top=tree[top][0];
}
}
}
return l=max(l,cnt[top]);
}
void solve()
{
scanf("%lld%lld",&n,&k);
for(int i=0;i<=tot;i++){
tree[i][0]=tree[i][1]=0;
cnt[i]=0;
}
tot=0;
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]=a[i-1]^a[i];
}
ll ans=1e18;
ll ansl = 0,ansr=0;
insert(0,0);
for(int i=1;i<=n;i++){
int l = search(a[i]);
if(l&&i-l<ans){
ans=i-l;
ansl=l+1;
ansr=i;
}
insert(a[i],i);
}
if(ans==1e18) puts("-1");
else printf("%lld %lld\n",ansl,ansr);
}