CF2093G

Solution

看到子串,想到双指针。因为求任意两个数异或的最大值是字典数的基本操作,比如这道题就是一个 01 字典树的例子。

考虑做法:

可以发现如果 $a_j=x$ 后删掉 $a_j$ 就不能往前移了,而在删掉 $a_j$ 之后即使还有符合的也已经大于 $ans$,可以不要考虑。

Code

#include<bits/stdc++.h>
using namespace std;
using LL=long long;
LL n,t,k,a[500005],ans;
struct trie{
	LL num=1,tr[5000005][2],cnt[5000005];
	inline LL node(){
		LL x=++num;
		tr[x][1]=tr[x][0]=cnt[x]=0;
		return x;
	}
	LL query(LL x){
		LL loc=1,res=0;
		for(int i=32;i>=0;i--){
			LL p=(x>>i)&1;
			if(cnt[tr[loc][p^1]]){
				p=p^1;
			}
			loc=tr[loc][p];
			res|=((p)<<i);
		}
		return res^x;
	}
	void add(LL x){
		LL loc= 1;
        for(int i = 32; i >= 0; i--) {
            LL p = (x >> i) & 1;
            if(!tr[loc][p]) {
                tr[loc][p] = node();
            }
            loc = tr[loc][p];
            cnt[loc]+=1;
        }
	}
	void del(LL x){
		LL loc= 1;
        for(int i = 32; i >= 0; i--) {
            LL p = (x >> i) & 1;
            if(!tr[loc][p]) {
                tr[loc][p] = node();
            }
            loc = tr[loc][p];
            cnt[loc]-=1;
        }
	}
}tree;
int main(){
	cin>>t;
	while(t--){
		ans=1e12;
		cin>>n>>k;
		for(int i=1;i<=n;i++) cin>>a[i];
		if(k==0){
			cout<<"1\n";
			continue;
		}
		
		tree.num=0,tree.node();
		for(int i=1,j=1;i<=n;i++){
			while(i>=j&&tree.query(a[i])>=k){
				ans=min(ans,LL(i-j+1));
				tree.del(a[j++]);
			}
			tree.add(a[i]);
		}
		cout<<(ans<=n ? ans : -1)<<endl;
	}
	return 0;
}