题意
给你n个数和k,问最短的区间长度,使得区间异或值>=k,输出左端点最小答案。
思路
对于每一个数,将其作为右端点,向左找满足条件的最靠右的左端点。
建立字典树,使用字典树完成上述操作。在插入元素时采用一个数组记录最靠右的端点。
清空操作在字典树中进行,防止超时
代码
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <iomanip>
#include <map>
#include <cstdio>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
#define endl '\n'
ll gcd(ll a, ll b){
return b == 0 ? a : gcd(b, a % b);
}
void input(){
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
}
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*f;
}
const int N = 1e5+10, M = N * 2, inf = 1e8;
int tr[N*32][2], idx, maxm[32*N];
ll n, a[N], t, k;
void insert(int x, int id){
int p = 0;
for(int i = 31; i >= 0; i--){
int u = x >> i & 1;
if(!tr[p][u]) {
tr[idx][0] = tr[idx][1] = 0; // 在字典树中清空
maxm[idx] = 0;
tr[p][u] = idx++;
}
p = tr[p][u];
maxm[p] = max(maxm[p], id); // 记录最靠右的取值
}
}
ll query(ll x){
int p = 0, res = 0;
for(int i = 31; i >= 0; i--){
int vx = (x >> i) & 1;
int vk = (k >> i) & 1;
// 此处列举x和k的当前位取值,分情况讨论
if(!vx){
if(!vk){
if(tr[p][1]) res = max(res, maxm[tr[p][1]]);
p = tr[p][0];
}else p = tr[p][1];
}else {
if(!vk){
if(tr[p][0]) res = max(res, maxm[tr[p][0]]);
p = tr[p][1];
}else p = tr[p][0];
}
if(!p) break;
}
if(p) res = max(res, maxm[p]);
return res;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
input();
cin>>t;
while(t--){
tr[0][0] = tr[0][1] = 0; idx = 1;
cin>>n>>k;
for(int i = 1; i <= n; i++) cin>>a[i];
for(int i = 1; i <= n; i++) a[i] ^= a[i-1];
int ansL = 0, ansR = n;
for(int i = 1; i <= n; i++){
if((a[i]^a[i-1]) >= k) {
ansL = i, ansR = i;
break;
}
int nxtL = query(a[i]);
if(nxtL > 0 && i - nxtL < ansR - ansL + 1){
ansL = nxtL + 1;
ansR = i;
}
insert(a[i], i);
}
if(ansL) cout<<ansL<<" "<<ansR<<endl;
else cout<<-1<<endl;
}
return 0;
}