D. Yet Another Problem
D. Yet Another Problem
You are given an array $a$ of $n$ integers $a_1,a_2,a_3, \ldots, a_n$.
You have to answer $q$ independent queries, each consisting of two integers $l$ and $r$.
- Consider the subarray $a[l:r] = [a_l,a_{l+1}, \ldots, a_r]$. You can apply the following operation to the subarray any number of times (possibly zero)-
- Choose two integers $L$, $R$ such that $l \leq L \leq R \leq r$ and $R−L+1$ is odd.
Replace each element in the subarray from $L$ to $R$ with the XOR of the elements in the subarray $[L,R]$.
The answer to the query is the minimum number of operations required to make all elements of the subarray $a[l:r]$ equal to $0$ or $−1$ if it is impossible to make all of them equal to $0$.
You can find more details about XOR operation here.
Input
The first line contains two integers $n$ and $q$ $(1 \leq n,q \leq 2 \cdot {10}^{5})$ — the length of the array $a$ and the number of queries.
The next line contains $n$ integers $a_1,a_2, \ldots ,a_n$ $(0 \leq a_i < 2^{30})$ — the elements of the array $a$.
The $i$-th of the next $q$ lines contains two integers $l_i$ and $r_i$ $(1 \leq l_i \leq r_i \leq n)$ — the description of the $i$-th query.
Output
For each query, output a single integer — the answer to that query.
Example
7 6 3 0 3 3 1 2 3 3 4 4 6 3 7 5 6 1 6 2 2
output
-1 1 1 -1 2 0
Note
In the first query, $l=3$,$r=4$, subarray $=$ $[3,3]$. We can apply operation only to the subarrays of length $1$, which won't change the array; hence it is impossible to make all elements equal to $0$.
In the second query, $l=4$,$r=6$, subarray $=$ $[3,1,2]$. We can choose the whole subarray $(L=4,R=6)$ and replace all elements by their XOR $(3 \oplus 1 \oplus 2) = 0$, making the subarray $[0,0,0]$.
In the fifth query, $l=1$,$r=6$, subarray $=$ $[3,0,3,3,1,2]$. We can make the operations as follows:
- Choose $L=4$,$R=6$, making the subarray $[3,0,3,0,0,0]$.
- Choose $L=1$,$R=5$, making the subarray $[0,0,0,0,0,0]$.
解题思路
这题最关键的地方是要看出来每一次操作都不会改变整个区间的异或和。
这是因为每次都选择一个长度为奇数的区间,然后将这个奇数区间中的每一个元素用奇数区间的异或和来代替,此时再求变化后的整个区间的异或和,可以发现此时的奇数区间的异或和结果就是原来没操作前的异或和,再异或上其他的元素就可以发现整个区间的异或和就是原来数组的异或和。
因此现在就可以判断出无解的情况。由于最后整个区间都要变成$0$,等价于整个区间的异或和为$0$,又因为每次操作都不会改变整个区间的异或和,因此如果整个区间的异或和不为$0$就无解。
接下来讨论的都是整个区间异或和为$0$的情况。
如果此时区间的全部元素均为$0$,那么只需要操作$0$次。
如果此时询问的区间长度为奇数,由于整个区间的异或和为$0$,因此只需操作$1$次(选择整个区间)。
如果区间的长度为偶数:
如果最左边的元素为$0$或最右边的元素为$0$,那么只需操作$1$次。
否则,我们找一下是否存在某个长度为奇数的前缀,这个前缀的异或和为$0$,如果存在,那么剩余部分(长度为奇数)的异或和也为$0$。再找一下是否存在某个长度为奇数的后缀,这个后缀的异或和为$0$,如果存在,那么剩余部分(长度为奇数)的异或和也为$0$。需要操作$2$次。
可以发现我们只需要看前缀就可以了,不需要把后缀的情况再考虑一遍。这是因为如果前缀的异或和为$0$,那么剩余部分就是奇数的后缀,而剩余的部分的异或和也为$0$,意味着存在一个奇数的后缀的异或和为$0$。即如果存在一个奇数的前缀的异或和为$0$,那么必然会存在一个奇数的后缀的异或和为$0$。为什么只判断前缀这种做法是对的呢,这是因为我们要把左端点的值变成$0$,意味着必然要对某个奇数的前缀进行操作。
那么如何找到是否存在某个前缀的异或和为$0$。假设有异或前缀和${sx}_i = a_1 \oplus a_2 \oplus \ldots \oplus a_i$,询问的区间是$[l, r]$,那么这个问题等价于找到一个$x \in [l, r]$且$x$的奇偶性与$l$相同,使得${sx}_{l - 1} \oplus {sx}_{x} = 0$,等价找到一个$x$使得${sx}_{l - 1} = {sx}_{x}$。那么我们可以一开始开两个哈希表$\text{std::unordered_map<int, std::vector<int>>}$,根据下标的奇偶性来记录异或前缀和为${sx}_i$时所对应的下标,到时候就可以二分出异或前缀和等于${sx}_{l-1}$的下标,最后看一下这个下标是否在范围内就可以了。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2e5 + 10; 7 8 int a[N], sx[N]; 9 LL s[N]; 10 11 int main() { 12 int n, m; 13 scanf("%d %d", &n, &m); 14 unordered_map<int, vector<int>> odd, even; 15 for (int i = 1; i <= n; i++) { 16 scanf("%d", a + i); 17 s[i] = s[i - 1] + a[i]; 18 sx[i] = sx[i - 1] ^ a[i]; 19 if (i & 1) odd[sx[i]].push_back(i); 20 else even[sx[i]].push_back(i); 21 } 22 23 while (m--) { 24 int l, r; 25 scanf("%d %d", &l, &r); 26 int ret = -1; 27 if (sx[r] ^ sx[l - 1]) { 28 ret = -1; 29 } 30 else if (s[r] - s[l - 1] == 0) { 31 ret = 0; 32 } 33 else if (r - l + 1 & 1) { 34 ret = 1; 35 } 36 else if (a[l] == 0 || a[r] == 0) { 37 ret = 1; 38 } 39 else { 40 if (l & 1) { 41 auto t = lower_bound(odd[sx[l - 1]].begin(), odd[sx[l - 1]].end(), l); 42 if (t != odd[sx[l - 1]].end() && *t <= r) ret = 2; 43 } 44 else { 45 auto t = lower_bound(even[sx[l - 1]].begin(), even[sx[l - 1]].end(), l); 46 if (t != even[sx[l - 1]].end() && *t <= r) ret = 2; 47 } 48 } 49 printf("%d\n", ret); 50 } 51 52 return 0; 53 }
参考资料
Codeforces Round #832 (Div. 2) A - D:https://zhuanlan.zhihu.com/p/580560085
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16884740.html