CF1968F 题解
倒数第一分钟提交成功,同时带我在 CF 的第 场比赛中上青,留念。
思路
异或的性质:
- ;
- ;
- 若 ,则 。
这题首先想到做一个前缀异或和,设 ,若 ,则一定有解,因为 一组,剩下的数一组即可。不然就一定得是奇数组,且每组的异或和都是 ,若是偶数组 就一定是 了。
接下来我们证明若可以分为奇数组数,则一定可以分为 组数:设 可以分为 组数,每组的异或和都是 ,则把任意 组连续的数合并为一组,结果不变,依然成立。
此时我们只要寻找两个分界点即可。定义一些 vector 数组 , 里存的是 时,递增的所有 。第一段 ,这一段的异或和是 ,所以 ,我们贪心地在 中二分找到第一个 的下标作为 ,若找不到或 则无解;然后继续二分找第二三段的分界线,我们又在 中找到第一个 的数作为 ,如果找不到或 则无解(此处 而不是 是因为第三段不能为空)。其它情况就有解了!
代码
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
int t, n, q, l, r, x, tmp, a[200005], tot;
map <int, int> mp;
vector <int> v[200005];
int main () {
ios::sync_with_stdio (0);
cin.tie (0);
cout.tie (0);
cin >> t;
while (t --) {
cin >> n >> q;
tot = 0, mp.clear ();
for (int i = 1; i <= n; ++ i) {
v[i].clear ();
cin >> a[i], a[i] ^= a[i - 1];
if (! mp[a[i]])
mp[a[i]] = ++ tot;
v[mp[a[i]]].emplace_back (i);
}
while (q --) {
cin >> l >> r;
if (! (a[r] ^ a[l - 1])) {
cout << "YES\n";
continue ;
}
tmp = mp[a[r]];
x = lower_bound (v[tmp].begin (), v[tmp].end (), l) - v[tmp].begin ();
if (x >= v[tmp].size () || v[tmp][x] >= r) {
cout << "NO\n";
continue ;
}
tmp = mp[a[l - 1]];
x = lower_bound (v[tmp].begin (), v[tmp].end (), v[mp[a[r]]][x]) - v[tmp].begin ();
if (x >= v[tmp].size () || v[tmp][x] >= r) {
cout << "NO\n";
continue ;
}
cout << "YES\n";
}
cout << '\n';
}
return 0;
}

浙公网安备 33010602011771号