📜  对于 M 个查询,范围 [L, R] 中 XOR + 1 等于 XOR (XOR) 1 的子数组计数

📅  最后修改于: 2022-05-13 01:56:04.496000             🧑  作者: Mango

对于 M 个查询,范围 [L, R] 中 XOR + 1 等于 XOR (XOR) 1 的子数组计数

给定一个数组,由N个正整数组成的arr[]和由两个整数组成的M个查询[L i , R i ] ,其中1 ≤ Li ≤ Ri ≤ N 。对于每个查询,找到范围[L i , R i ](X+1)=(X⊕1)的子数组的数量,其中X表示子数组的异或。

天真的方法:对于每个查询,选择给定的范围 [L i , R i ] 并为每个子数组检查它是否满足给定条件。
时间复杂度: O(N 3 * M)

有效的方法:在上述问题中,可以进行以下观察:

  • 为了满足给定条件, X必须是偶数,因为
    • 如果X是偶数,则( X ⊕1)=( X +1)
    • 如果X是奇数,则( X ⊕1)=( X -1)
  • 对于子数组,即使该子数组中奇数的计数是偶数,它的异或也会是偶数。
  • 如果奇数的计数是偶数,则子数组的总和将为偶数。因此,具有偶数和的子数组就是这个问题的答案。

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
using namespace std;
 
vector countXorSubarr(
    vector arr,
    vector > queries,
    int n, int m)
{
 
    // As queries are in 1-based indexing,
    // add one dummy entry in beginning
    // of arr to make it 1-indexed
    arr.insert(arr.begin(), 0);
 
    // sum[] will contain parity
    // of prefix sum till index i
    // count[] will contain
    // number of 0s in sum[]
    int count[n + 1], sum[n + 1];
    count[0] = sum[0] = 0;
 
    for (int i = 1; i <= n; i++) {
 
        // Take the parity of current sum
        sum[i] = (sum[i - 1] + arr[i]) % 2;
        count[i] = count[i - 1];
 
        // If current parity is even,
        // increase the count
        if (sum[i] % 2 == 0)
            count[i]++;
    }
 
    // Array to hold the answer of 'm' queries
    vector ans;
 
    // Iterate through queries and use handshake
    // lemma to count even sum subarrays
    // ( Note that an even sum can
    // be formed by two even or two odd )
    for (vector qu : queries) {
        int L = qu[0], R = qu[1];
 
        // Find count of even and
        // odd sums in range [L, R]
        int even = count[R] - count[L - 1];
        int odd = (R - L + 1) - even;
 
        // If prefix sum at L-1 is odd,
        // then we need to swap
        // our counts of odd and even
        if (sum[L - 1] == 1)
            swap(even, odd);
 
        // Taking no element is also
        // considered an even sum
        // so even will be increased by 1
        // (This is the condition when
        // a prefix of even sum is taken)
        even++;
 
        // Find number of ways to
        // select two even's or two odd's
        int subCount = (even * (even - 1)) / 2
                       + (odd * (odd - 1)) / 2;
 
        ans.push_back(subCount);
    }
 
    return ans;
}
 
// Driver code
int main()
{
    int n = 5;
    vector arr = { 1, 2, 9, 8, 7 };
    int m = 2;
    vector > queries
        = { { 1, 5 }, { 3, 4 } };
 
    // Function call and print answer
    vector ans
        = countXorSubarr(arr, queries, n, m);
    for (int x : ans)
        cout << x << " ";
    cout << endl;
 
    return 0;
}


Java
// Java program for the above approach
import java.util.ArrayList;
 
class GFG
{
 
    public static ArrayList countXorSubarr(int[] arr, int[][] queries, int n, int m) {
 
        // As queries are in 1-based indexing,
        // add one dummy entry in beggining
        // of arr to make it 1-indexed
        // arr.insert(arr.begin(), 0);
        int[] temp_arr = new int[arr.length + 1];
        temp_arr[0] = 0;
        for (int i = 1; i < temp_arr.length; i++) {
            temp_arr[i] = arr[i - 1];
        }
        arr = temp_arr.clone();
 
        // sum[] will contain parity
        // of prefix sum till index i
        // count[] will contain
        // number of 0s in sum[]
        int[] count = new int[n + 1];
        int[] sum = new int[n + 1];
        count[0] = sum[0] = 0;
 
        for (int i = 1; i <= n; i++) {
 
            // Take the parity of current sum
            sum[i] = (sum[i - 1] + arr[i]) % 2;
            count[i] = count[i - 1];
 
            // If current parity is even,
            // increase the count
            if (sum[i] % 2 == 0)
                count[i]++;
        }
 
        // Array to hold the answer of 'm' queries
        ArrayList ans = new ArrayList();
 
        // Iterate through queries and use handshake
        // lemma to count even sum subarrays
        // ( Note that an even sum can
        // be formed by two even or two odd )
        for (int[] qu : queries) {
            int L = qu[0], R = qu[1];
 
            // Find count of even and
            // odd sums in range [L, R]
            int even = count[R] - count[L - 1];
            int odd = (R - L + 1) - even;
 
            // If prefix sum at L-1 is odd,
            // then we need to swap
            // our counts of odd and even
            if (sum[L - 1] == 1) {
                int temp = even;
                even = odd;
                odd = temp;
            }
 
            // Taking no element is also
            // considered an even sum
            // so even will be increased by 1
            // (This is the condition when
            // a prefix of even sum is taken)
            even++;
 
            // Find number of ways to
            // select two even's or two odd's
            int subCount = (even * (even - 1)) / 2 + (odd * (odd - 1)) / 2;
 
            ans.add(subCount);
        }
 
        return ans;
    }
 
    // Driver code
    public static void main(String args[])
    {
        int n = 5;
        int[] arr = { 1, 2, 9, 8, 7 };
        int m = 2;
        int[][] queries = { { 1, 5 }, { 3, 4 } };
 
        // Function call and print answer
        ArrayList ans = countXorSubarr(arr, queries, n, m);
        for (int x : ans)
            System.out.print(x + " ");
        System.out.println("");
 
    }
}
 
// This code is contributed by saurabh_jaiswal.


Python3
# python program for the above approach
import math
def countXorSubarr(arr, queries, n, m):
 
        # As queries are in 1-based indexing,
        # add one dummy entry in beggining
        # of arr to make it 1-indexed
    arr.insert(0, 0)
 
    # sum[] will contain parity
    # of prefix sum till index i
    # count[] will contain
    # number of 0s in sum[]
    count = [0 for _ in range(n + 1)]
    sum = [0 for _ in range(n + 1)]
 
    for i in range(1, n+1):
 
                # Take the parity of current sum
        sum[i] = (sum[i - 1] + arr[i]) % 2
        count[i] = count[i - 1]
 
        # If current parity is even,
        # increase the count
        if (sum[i] % 2 == 0):
            count[i] += 1
 
        # Array to hold the answer of 'm' queries
    ans = []
 
    # Iterate through queries and use handshake
    # lemma to count even sum subarrays
    # ( Note that an even sum can
    # be formed by two even or two odd )
    for qu in queries:
 
        L = qu[0]
        R = qu[1]
 
        # Find count of even and
        # odd sums in range [L, R]
        even = count[R] - count[L - 1]
        odd = (R - L + 1) - even
 
        # If prefix sum at L-1 is odd,
        # then we need to swap
        # our counts of odd and even
        if (sum[L - 1] == 1):
            temp = even
            even = odd
            odd = temp
 
            # Taking no element is also
            # considered an even sum
            # so even will be increased by 1
            # (This is the condition when
            # a prefix of even sum is taken)
        even += 1
 
        # Find number of ways to
        # select two even's or two odd's
        subCount = (even * (even - 1)) // 2 + (odd * (odd - 1)) // 2
        ans.append(subCount)
    return ans
 
# Driver code
if __name__ == "__main__":
 
    n = 5
    arr = [1, 2, 9, 8, 7]
    m = 2
    queries = [[1, 5], [3, 4]]
 
    # Function call and print answer
    ans = countXorSubarr(arr, queries, n, m)
    for x in ans:
        print(x, end=" ")
 
    # This code is contributed by rakeshsahni


C#
// C# program for the above approach
using System;
using System.Collections.Generic;
 
public class GFG
{
 
    public static List countXorSubarr(int[] arr, int[,] queries, int n, int m)
    {
 
        // As queries are in 1-based indexing,
        // add one dummy entry in beggining
        // of arr to make it 1-indexed
        // arr.insert(arr.begin(), 0);
        int[] temp_arr = new int[arr.Length + 1];
        temp_arr[0] = 0;
        for (int i = 1; i < temp_arr.Length; i++) {
            temp_arr[i] = arr[i - 1];
        }
        arr = temp_arr;
 
        // sum[] will contain parity
        // of prefix sum till index i
        // []count will contain
        // number of 0s in sum[]
        int[] count = new int[n + 1];
        int[] sum = new int[n + 1];
        count[0] = sum[0] = 0;
 
        for (int i = 1; i <= n; i++) {
 
            // Take the parity of current sum
            sum[i] = (sum[i - 1] + arr[i]) % 2;
            count[i] = count[i - 1];
 
            // If current parity is even,
            // increase the count
            if (sum[i] % 2 == 0)
                count[i]++;
        }
 
        // Array to hold the answer of 'm' queries
        List ans = new List();
 
        // Iterate through queries and use handshake
        // lemma to count even sum subarrays
        // ( Note that an even sum can
        // be formed by two even or two odd )
         
        for(int i = 0; i < queries.GetLength(0); i++)
        {
            int L = queries[i,0], R = queries[i,1];
 
            // Find count of even and
            // odd sums in range [L, R]
            int even = count[R] - count[L - 1];
            int odd = (R - L + 1) - even;
 
            // If prefix sum at L-1 is odd,
            // then we need to swap
            // our counts of odd and even
            if (sum[L - 1] == 1) {
                int temp = even;
                even = odd;
                odd = temp;
            }
 
            // Taking no element is also
            // considered an even sum
            // so even will be increased by 1
            // (This is the condition when
            // a prefix of even sum is taken)
            even++;
 
            // Find number of ways to
            // select two even's or two odd's
            int subCount = (even * (even - 1)) / 2 + (odd * (odd - 1)) / 2;
 
            ans.Add(subCount);
         
        }
        return ans;
    }
      public static int[] GetRow(int[,] matrix, int row)
      {
        var rowLength = matrix.GetLength(1);
        var rowVector = new int[rowLength];
 
        for (var i = 0; i < rowLength; i++)
          rowVector[i] = matrix[row, i];
 
        return rowVector;
      }
   
    // Driver code
    public static void Main(String []args)
    {
        int n = 5;
        int[] arr = { 1, 2, 9, 8, 7 };
        int m = 2;
        int[,] queries = { { 1, 5 }, { 3, 4 } };
 
        // Function call and print answer
        List ans = countXorSubarr(arr, queries, n, m);
        foreach (int x in ans)
            Console.Write(x + " ");
        Console.WriteLine("");
 
    }
}
 
// This code contributed by shikhasingrajput


Javascript


输出
6 1 

时间复杂度: O(N+M)
辅助空间: O(N+M)