题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6955
分析
用字典树存下每个前缀异或,每次放入建树的时候给每个点一个最新的标号。
每次加入后进行查询,判断是否有数可以使其达到大于等于k的目的,每次更新最右边的符合的位置。
具体看代码。
代码
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define MP make_pair
#define pb push_back
typedef long long ll;
int n,B = 31;
int ans,cnt;
pair<int,int> res;
ll a[100005],k;
int tree[100000005][2], mr[100000005];
void add(ll qq, int p)
{
int len=B,rt=0;
bool x;
for (int i=len;i>=0;i--)
{
mr[rt] = p;
x = qq & (1ll << i);
if(!tree[rt][x]) tree[rt][x] = ++cnt;
rt = tree[rt][x];
}
mr[rt] = p;
}
int que(ll x) {
int res = -1, flag = 1, rt = 0;
for(int i=B;i>=0;i--)
{
bool v1 = x & (1ll << i);
bool v2 = k & (1ll << i);
if(v2 == 0)
{
if(v1 == 0 && tree[rt][1])
{
res = max(res, mr[tree[rt][1]]);
if(tree[rt][0]) rt = tree[rt][0];
else
{
flag = 0;
break;
}
}
else if(v1 == 1 && tree[rt][0])
{
res = max(res, mr[tree[rt][0]]);
if(tree[rt][1]) rt = tree[rt][1];
else
{
flag = 0;
break;
}
}
else if(v1 == 0 && tree[rt][0]) rt = tree[rt][0];
else if(v1 == 1 && tree[rt][1]) rt = tree[rt][1];
}
else
{
if(v1 == 0 && tree[rt][1]) rt = tree[rt][1];
else if(v1 == 1 && tree[rt][0]) rt = tree[rt][0];
else
{
flag = 0;
break;
}
}
}
if(flag == 1) res = max(res, mr[rt]);
return res;
}
int main ()
{
int T;
scanf("%d",&T);
int last = 0;
while (T--)
{
for(int i=0;i<=last;i++) mr[i] = tree[i][0] = tree[i][1] = 0;
ans = 1e9;
res = MP(0, 0);
scanf("%d%lld",&n,&k);
cnt=0;
for(int i=1;i<=n;i++) scanf("%lld",&a[i]), a[i] = a[i - 1] ^ a[i];
add(0, 0);
int left;
for(int i=1;i<=n;i++)
{
add(a[i], i);
left = que(a[i]);
if(left == -1) continue;
if(i - left < ans) ans = i - left, res = MP(left + 1, i);
}
if(ans != 1e9) printf ("%d %d\n",res.fi, res.se);
else printf("-1\n");
last = cnt;
}
return 0;
}