2021杭电大学生程序设计超级联赛01 F Xor sum
F - Xor sum
discription
Given a sequence of integers of length n, find the shortest consecutive subsequence witch XOR sum not less than k.
If there are multiple consecutive subsequences of the same length, print the consecutive subsequence with the smallest left end point.
If there are no consecutive subsequence witch XOR sum not less than k, just print "-1".
Input
The first line contains a single integer t (t<=100) representing the number of test cases in the input. Then t test cases follow.
The first line of each test case contains two integers n (1<=n<=100000) and k (0<=k<2^30), representing the length of sequence.
The second line of each test contains n integers ai (0<=ai<2^30), representing the integers in sequence.
The number of test witch n>1000 does not exceed 5.
Output
For each test case, print two integers in one line, representing the left end point and right end point of the consecutive subsequence.
If there are no consecutive subsequence witch XOR sum not less than k, print "-1" in one line.
题目大意
给出一系列数,求最短连续区间,使区间异或和大于等于k
解题思路
01字典树
从左到右枚举,使当前位置为区间右边界,同时在左侧区域维护一个01字典树,在字典树中找出满足要求的最大的左边界。时间复杂度为O(nlogn)
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 1e5;
const int MAXM = 3e6; //len * N的空间 即30*1e5
const int maxbit = 29;
int a[MAXN + 10]; //储存前缀异或
int p[MAXM + 10][2]; //01字典树
int mx[MAXM + 10];
void solve() {
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] ^= a[i - 1];
}
int ansl = -1, ansr = n;
int cnt = 1;
p[1][0] = p[1][1] = 0;
mx[1] = -1;
for (int i = 0; i <= n; i++) {
int x = 1, res = -1; //x:字典树上节点 res:当前得到满足异或和大于K的区间最右侧的左边界
for (int j = maxbit; j >= 0; j--) { //01字典树的查询操作,找出满足异或和大于k的区间的 最靠右的 左侧
int cur = (a[i] >> j) & 1; //依次取出a[i]每一位
if (!((k >> j) & 1)) { //如果k对应的位上是0,有机会通过将cur ^ (cur ^ 1),得到一个大于k的值,进入if
if (p[x][cur ^ 1]) { //cur ^ 1 存在,更新左边界的值
res = max(res, mx[p[x][cur ^ 1]]);
}
x = p[x][cur]; //进入下一层
}
else //没机会,直接进入下一层
x = p[x][cur ^ 1];
if (!x) //字典树串取完了,退出
break;
}
if (x)
res = max(res, mx[x]);
if (res >= 0 && i - res < ansr - ansl) { //res被更新过,新区间更小,更新答案
ansl = res;
ansr = i;
}
x = 1;
for (int j = maxbit; j >= 0; j--) {
int cur = (a[i] >> j) & 1; //同查找中的相同语句
if (!p[x][cur]) { //插入新节点
p[x][cur] = ++cnt; //初始化
mx[cnt] = -1; //
p[cnt][0] = p[cnt][1] = 0; //
}
x = p[x][cur];
mx[x] = max(mx[x], i); //更新已有节点 最右侧位置
}
}
if (ansl >= 0)
printf("%d %d\n", ansl + 1, ansr);
else
printf("-1\n"); //ansl没被更新过,无解
}
int main() {
int _t;
scanf("%d", &_t);
while (_t--) { //多组数据
solve();
}
return 0;
}

浙公网安备 33010602011771号