D. Yet Another Problem

D. Yet Another Problem

You are given an array a of n integers a1,a2,a3,,an.

You have to answer q independent queries, each consisting of two integers l and r.

  1. Consider the subarray a[l:r]=[al,al+1,,ar]. You can apply the following operation to the subarray any number of times (possibly zero)-
  2. Choose two integers L, R such that lLRr and RL+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 (1n,q2105) — the length of the array a and the number of queries.

The next line contains n integers a1,a2,,an (0ai<230) — the elements of the array a.

The i-th of the next q lines contains two integers li and ri (1lirin) — 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 (312)=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:

  1. Choose L=4,R=6, making the subarray [3,0,3,0,0,0].
  2. 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。假设有异或前缀和sxi=a1a2ai,询问的区间是[l,r],那么这个问题等价于找到一个x[l,r]x的奇偶性与l相同,使得sxl1sxx=0,等价找到一个x使得sxl1=sxx。那么我们可以一开始开两个哈希表std::unordered_map<int, std::vector<int>>,根据下标的奇偶性来记录异或前缀和为sxi时所对应的下标,到时候就可以二分出异或前缀和等于sxl1的下标,最后看一下这个下标是否在范围内就可以了。

  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

posted @   onlyblues  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示