给定一个N * N矩阵和q个查询,每个查询包含一个矩形子矩阵的左上角和右下角的位置,任务是从该子矩阵中查找所有元素的异或。
例子:
Input: arr[][] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, q[] = {{1, 1, 2, 2}, {1, 2, 2, 2}}
Output:
2
15
Query 1: 5 ^ 6 ^ 8 ^ 9 = 2
Query 2: 6 ^ 9 = 15
Input: arr[][] = {{21, 2}, { 14, 5}}, q[] = {{0, 1, 1, 1}, {0, 0, 1, 1}}
Output:
7
28
一个简单的解决方案是为每个查询找到整个子矩阵的XOR。因此,每个查询的最坏情况时间复杂度将为O(n 2 )。
高效的方法:我们都熟悉线性数组上的前缀XOR的想法,即
if arr[] = {1, 2, 3, 4} and we calculate prefixXOR[] = {1, 3, 0, 4} where prefixXOR[i] stores the XOR of values from arr[0] to arr[i]
Then the XOR of sub-array arr[i] to arr[j] can be found as prefixXOR[j] ^ prefixXOR[i – 1]
For example, the XOR of sub-array {2, 3} will be XOR(0, 1) = 1
This is because in the prefixXOR values for {1, 2, 3} and {1}, the value 1 got repeated twice which will give 0 as the XOR result and will not affect the value of the other XOR operations.
我们将尝试将其扩展到二维矩阵。我们将计算一个前缀XOR矩阵,这将有助于我们解决O(1)中的每个查询。
在这种情况下,我们在(R,C)位置的前缀XOR矩阵将存储矩形子矩阵的XOR,其左上角位于(0,0),右下角位于(R,C)。
我们分两步计算前缀XOR。
- 从左到右为原始矩阵的每一行计算prefix-XOR。
- 在上面的矩阵上,从上到下为每列计算前缀XOR。
一旦有了所需的前缀XOR-matrix,我们就可以简单地回答查询。从(R1,C1)到(R2,C2)的子矩阵的XOR可以计算为prefix_xor [R2] [C2] ^ prefix_xor [R1-1 –] [C2] ^ prefix_xor [R2] [C1-1] ^ prefix_xor [R1 – 1] [C1 – 1] 。
注意:如果R1或C1等于0,则R1 – 1或C1 – 1也应为0。
下面是上述方法的实现:
C++
// C++ implementation of the approach
#include
#define n 3
using namespace std;
// Function to pre-compute the xor
void preComputeXor(int arr[][n], int prefix_xor[][n])
{
// Left to right prefix xor
// for each row
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
if (j == 0)
prefix_xor[i][j] = arr[i][j];
else
prefix_xor[i][j]
= (prefix_xor[i][j - 1] ^ arr[i][j]);
}
// Top to bottom prefix xor
// for each column
for (int i = 0; i < n; i++)
for (int j = 1; j < n; j++)
prefix_xor[j][i]
= (prefix_xor[j - 1][i] ^ prefix_xor[j][i]);
}
// Function to process the queries
// x1, x2, y1, y2 represent the
// positions of the top-left
// and bottom right corners
int ansQuerie(int prefix_xor[][n], int x1, int y1, int x2, int y2)
{
// To store the xor values
int xor_1 = 0, xor_2 = 0, xor_3 = 0;
// Finding the values we need to xor
// with value at (x2, y2) in prefix-xor
// matrix
if (x1 != 0)
xor_1 = prefix_xor[x1 - 1][y2];
if (y1 != 0)
xor_2 = prefix_xor[x2][y1 - 1];
if (x1 != 0 and y1 != 0)
xor_3 = prefix_xor[x1 - 1][y1 - 1];
// Return the required prefix xor
return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3));
}
// Driver code
int main()
{
int arr[][n] = { { 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 } };
// To store pre-computed xor
int prefix_xor[n][n];
// Pre-computing xor
preComputeXor(arr, prefix_xor);
// Queries
cout << ansQuerie(prefix_xor, 1, 1, 2, 2) << endl;
cout << ansQuerie(prefix_xor, 1, 2, 2, 2) << endl;
return 0;
}
Java
// Java implementation of the approach
class GfG
{
static int n = 3;
// Function to pre-compute the xor
static void preComputeXor(int arr[][],
int prefix_xor[][])
{
// Left to right prefix xor
// for each row
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
if (j == 0)
prefix_xor[i][j] = arr[i][j];
else
prefix_xor[i][j] =
(prefix_xor[i][j - 1] ^ arr[i][j]);
}
// Top to bottom prefix xor
// for each column
for (int i = 0; i < n; i++)
for (int j = 1; j < n; j++)
prefix_xor[j][i] =
(prefix_xor[j - 1][i] ^ prefix_xor[j][i]);
}
// Function to process the queries
// x1, x2, y1, y2 represent the
// positions of the top-left
// and bottom right corners
static int ansQuerie(int prefix_xor[][], int x1,
int y1, int x2, int y2)
{
// To store the xor values
int xor_1 = 0, xor_2 = 0, xor_3 = 0;
// Finding the values we need to xor
// with value at (x2, y2) in prefix-xor
// matrix
if (x1 != 0)
xor_1 = prefix_xor[x1 - 1][y2];
if (y1 != 0)
xor_2 = prefix_xor[x2][y1 - 1];
if (x1 != 0 && y1 != 0)
xor_3 = prefix_xor[x1 - 1][y1 - 1];
// Return the required prefix xor
return ((prefix_xor[x2][y2] ^ xor_1) ^ (xor_2 ^ xor_3));
}
// Driver code
public static void main(String[] args)
{
int arr[][] = new int[][]{{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }};
// To store pre-computed xor
int prefix_xor[][] = new int[n][n];
// Pre-computing xor
preComputeXor(arr, prefix_xor);
// Queries
System.out.println(ansQuerie(prefix_xor, 1, 1, 2, 2));
System.out.println(ansQuerie(prefix_xor, 1, 2, 2, 2));
}
}
// This code is contributed by
// Prerna Saini.
Python3
n = 3
# Function to pre-compute the xor
def preComputeXor(arr, prefix_xor):
# Left to right prefix xor
# for each row
for i in range(n):
for j in range(n):
if (j == 0):
prefix_xor[i][j] = arr[i][j]
else:
prefix_xor[i][j] = (prefix_xor[i][j - 1] ^
arr[i][j])
# Top to bottom prefix xor
# for each column
for i in range(n):
for j in range(1, n):
prefix_xor[j][i] = (prefix_xor[j - 1][i] ^
prefix_xor[j][i])
# Function to process the queries
# x1, x2, y1, y2 represent the
# positions of the top-left
# and bottom right corners
def ansQuerie(prefix_xor, x1, y1, x2, y2):
# To store the xor values
xor_1, xor_2, xor_3 = 0, 0, 0
# Finding the values we need to xor
# with value at (x2, y2) in prefix-xor
# matrix
if (x1 != 0):
xor_1 = prefix_xor[x1 - 1][y2]
if (y1 != 0):
xor_2 = prefix_xor[x2][y1 - 1]
if (x1 != 0 and y1 != 0):
xor_3 = prefix_xor[x1 - 1][y1 - 1]
# Return the required prefix xor
return ((prefix_xor[x2][y2] ^ xor_1) ^
(xor_2 ^ xor_3))
# Driver code
arr = [[ 1, 2, 3 ],
[ 4, 5, 6 ],
[ 7, 8, 9 ]]
# To store pre-computed xor
prefix_xor = [[0 for i in range(n)]
for i in range(n)]
# Pre-computing xor
preComputeXor(arr, prefix_xor)
# Queries
print(ansQuerie(prefix_xor, 1, 1, 2, 2))
print(ansQuerie(prefix_xor, 1, 2, 2, 2))
# This code is contributed by Mohit Kumar
C#
// C# implementation of the approach
using System;
class GfG
{
static int n = 3;
// Function to pre-compute the xor
static void preComputeXor(int [,]arr,
int [,]prefix_xor)
{
// Left to right prefix xor
// for each row
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
{
if (j == 0)
prefix_xor[i, j] = arr[i, j];
else
prefix_xor[i, j] =
(prefix_xor[i, j - 1] ^ arr[i, j]);
}
// Top to bottom prefix xor
// for each column
for (int i = 0; i < n; i++)
for (int j = 1; j < n; j++)
prefix_xor[j, i] =
(prefix_xor[j - 1, i] ^
prefix_xor[j, i]);
}
// Function to process the queries
// x1, x2, y1, y2 represent the
// positions of the top-left
// and bottom right corners
static int ansQuerie(int [,]prefix_xor, int x1,
int y1, int x2, int y2)
{
// To store the xor values
int xor_1 = 0, xor_2 = 0, xor_3 = 0;
// Finding the values we need to xor
// with value at (x2, y2) in prefix-xor
// matrix
if (x1 != 0)
xor_1 = prefix_xor[x1 - 1, y2];
if (y1 != 0)
xor_2 = prefix_xor[x2, y1 - 1];
if (x1 != 0 && y1 != 0)
xor_3 = prefix_xor[x1 - 1, y1 - 1];
// Return the required prefix xor
return ((prefix_xor[x2,y2] ^ xor_1) ^
(xor_2 ^ xor_3));
}
// Driver code
public static void Main()
{
int [,]arr = {{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }};
// To store pre-computed xor
int [,]prefix_xor = new int[n, n];
// Pre-computing xor
preComputeXor(arr, prefix_xor);
// Queries
Console.WriteLine(ansQuerie(prefix_xor, 1, 1, 2, 2));
Console.WriteLine(ansQuerie(prefix_xor, 1, 2, 2, 2));
}
}
// This code is contributed by Ryuga
PHP
2
15