给定一个长度为N的数组 A[] ,其中 N 是偶数,任务是回答Q 个独立的查询,其中每个查询由一个正整数K组成, K表示对数组执行的循环移位的次数,并找到元素的总和通过对分割后的数组执行按位或运算。
注意:每个查询都以原始数组开始。
例子:
Input: A[] = {12, 23, 4, 21, 22, 76}, Q = 1, K = 2
Output: 117
Explanation:
Since K is 2, modified array A[]={22, 76, 12, 23, 4, 21}.
Bitwise OR of first half of array = (22 | 76 | 12) = 94
Bitwise OR of second half of array = (21 | 23 | 4) = 23
Sum of OR values is 94 + 23 = 117
Input: A[] = {7, 44, 19, 86, 65, 39, 75, 101}, Q = 1, K = 4
Output: 238
Since K is 4, modified array A[]={65, 39, 75, 101, 7, 44, 19, 86}.
Bitwise OR of first half of array = 111
Bitwise OR of second half of array = 127
Sum of OR values is 111 + 127 = 238
天真的方法:
要解决上述问题,最简单的方法是将数组的每个元素移动K % (N / 2) ,然后遍历数组以计算每个查询的两半的 OR。但这种方法效率不高,因此可以进一步优化。
有效的方法:
为了优化上述方法,我们可以借助 Segment Tree 数据结构。
Observation:
- We can observe that after exactly N / 2 right circular shifts the two halves of the array become the same as in the original array. This effectively reduces the number of rotations to K % (N / 2).
- Performing a right circular shift is basically shifting the last element of the array to the front. So for any positive integer X performing X right circular shifts is equal to shifting the last X elements of the array to the front.
以下是解决问题的步骤:
- 为原始数组A[]构造一个段树并分配一个变量,假设i = K % (N / 2) 。
- 然后对于每个查询,我们使用按位 OR 查找的段树;即从第一个(N / 2) – i – 1 个元素的末尾OR按位 OR 对 i 个元素进行按位或。
- 然后计算[(N / 2) – i, N – i – 1]范围内元素的按位或。
- 将两个结果相加得到第 i 个查询的答案。
下面是上述方法的实现:
C++
// C++ Program to find Bitwise OR of two
// equal halves of an array after performing
// K right circular shifts
#include
const int MAX = 100005;
using namespace std;
// Array for storing
// the segment tree
int seg[4 * MAX];
// Function to build the segment tree
void build(int node, int l, int r, int a[])
{
if (l == r)
seg[node] = a[l];
else {
int mid = (l + r) / 2;
build(2 * node, l, mid, a);
build(2 * node + 1, mid + 1, r, a);
seg[node] = (seg[2 * node]
| seg[2 * node + 1]);
}
}
// Function to return the OR
// of elements in the range [l, r]
int query(int node, int l, int r,
int start, int end, int a[])
{
// Check for out of bound condition
if (l > end or r < start)
return 0;
if (start <= l and r <= end)
return seg[node];
// Find middle of the range
int mid = (l + r) / 2;
// Recurse for all the elements in array
return ((query(2 * node, l, mid,
start, end, a))
| (query(2 * node + 1, mid + 1,
r, start, end, a)));
}
// Function to find the OR sum
void orsum(int a[], int n, int q, int k[])
{
// Function to build the segment Tree
build(1, 0, n - 1, a);
// Loop to handle q queries
for (int j = 0; j < q; j++) {
// Effective number of
// right circular shifts
int i = k[j] % (n / 2);
// Calculating the OR of
// the two halves of the
// array from the segment tree
// OR of second half of the
// array [n/2-i, n-1-i]
int sec = query(1, 0, n - 1,
n / 2 - i, n - i - 1, a);
// OR of first half of the array
// [n-i, n-1]OR[0, n/2-1-i]
int first = (query(1, 0, n - 1, 0,
n / 2 - 1 - i, a)
| query(1, 0, n - 1,
n - i, n - 1, a));
int temp = sec + first;
// Print final answer to the query
cout << temp << endl;
}
}
// Driver Code
int main()
{
int a[] = { 7, 44, 19, 86, 65, 39, 75, 101 };
int n = sizeof(a) / sizeof(a[0]);
int q = 2;
int k[q] = { 4, 2 };
orsum(a, n, q, k);
return 0;
}
Java
// Java program to find Bitwise OR of two
// equal halves of an array after performing
// K right circular shifts
import java.util.*;
class GFG{
static int MAX = 100005;
// Array for storing
// the segment tree
static int []seg = new int[4 * MAX];
// Function to build the segment tree
static void build(int node, int l,
int r, int a[])
{
if (l == r)
seg[node] = a[l];
else
{
int mid = (l + r) / 2;
build(2 * node, l, mid, a);
build(2 * node + 1, mid + 1, r, a);
seg[node] = (seg[2 * node] |
seg[2 * node + 1]);
}
}
// Function to return the OR
// of elements in the range [l, r]
static int query(int node, int l, int r,
int start, int end, int a[])
{
// Check for out of bound condition
if (l > end || r < start)
return 0;
if (start <= l && r <= end)
return seg[node];
// Find middle of the range
int mid = (l + r) / 2;
// Recurse for all the elements in array
return ((query(2 * node, l, mid,
start, end, a)) |
(query(2 * node + 1, mid + 1,
r, start, end, a)));
}
// Function to find the OR sum
static void orsum(int a[], int n,
int q, int k[])
{
// Function to build the segment Tree
build(1, 0, n - 1, a);
// Loop to handle q queries
for(int j = 0; j < q; j++)
{
// Effective number of
// right circular shifts
int i = k[j] % (n / 2);
// Calculating the OR of
// the two halves of the
// array from the segment tree
// OR of second half of the
// array [n/2-i, n-1-i]
int sec = query(1, 0, n - 1,
n / 2 - i,
n - i - 1, a);
// OR of first half of the array
// [n-i, n-1]OR[0, n/2-1-i]
int first = (query(1, 0, n - 1, 0,
n / 2 - 1 - i, a) |
query(1, 0, n - 1,
n - i, n - 1, a));
int temp = sec + first;
// Print final answer to the query
System.out.print(temp + "\n");
}
}
// Driver Code
public static void main(String[] args)
{
int a[] = { 7, 44, 19, 86, 65, 39, 75, 101 };
int n = a.length;
int q = 2;
int k[] = { 4, 2 };
orsum(a, n, q, k);
}
}
// This code is contributed by 29AjayKumar
Python3
# Python3 program to find Bitwise OR of two
# equal halves of an array after performing
# K right circular shifts
MAX = 100005
# Array for storing
# the segment tree
seg = [0] * (4 * MAX)
# Function to build the segment tree
def build(node, l, r, a):
if (l == r):
seg[node] = a[l]
else:
mid = (l + r) // 2
build(2 * node, l, mid, a)
build(2 * node + 1, mid + 1, r, a)
seg[node] = (seg[2 * node] |
seg[2 * node + 1])
# Function to return the OR
# of elements in the range [l, r]
def query(node, l, r, start, end, a):
# Check for out of bound condition
if (l > end or r < start):
return 0
if (start <= l and r <= end):
return seg[node]
# Find middle of the range
mid = (l + r) // 2
# Recurse for all the elements in array
return ((query(2 * node, l, mid,
start, end, a)) |
(query(2 * node + 1, mid + 1,
r, start, end, a)))
# Function to find the OR sum
def orsum(a, n, q, k):
# Function to build the segment Tree
build(1, 0, n - 1, a)
# Loop to handle q queries
for j in range(q):
# Effective number of
# right circular shifts
i = k[j] % (n // 2)
# Calculating the OR of
# the two halves of the
# array from the segment tree
# OR of second half of the
# array [n/2-i, n-1-i]
sec = query(1, 0, n - 1, n // 2 - i,
n - i - 1, a)
# OR of first half of the array
# [n-i, n-1]OR[0, n/2-1-i]
first = (query(1, 0, n - 1, 0,
n // 2 -
1 - i, a) |
query(1, 0, n - 1,
n - i,
n - 1, a))
temp = sec + first
# Print final answer to the query
print(temp)
# Driver Code
if __name__ == "__main__":
a = [ 7, 44, 19, 86, 65, 39, 75, 101 ]
n = len(a)
q = 2
k = [ 4, 2 ]
orsum(a, n, q, k)
# This code is contributed by chitranayal
C#
// C# program to find Bitwise OR of two
// equal halves of an array after performing
// K right circular shifts
using System;
class GFG{
static int MAX = 100005;
// Array for storing
// the segment tree
static int []seg = new int[4 * MAX];
// Function to build the segment tree
static void build(int node, int l,
int r, int []a)
{
if (l == r)
seg[node] = a[l];
else
{
int mid = (l + r) / 2;
build(2 * node, l, mid, a);
build(2 * node + 1, mid + 1, r, a);
seg[node] = (seg[2 * node] |
seg[2 * node + 1]);
}
}
// Function to return the OR
// of elements in the range [l, r]
static int query(int node, int l, int r,
int start, int end, int []a)
{
// Check for out of bound condition
if (l > end || r < start)
return 0;
if (start <= l && r <= end)
return seg[node];
// Find middle of the range
int mid = (l + r) / 2;
// Recurse for all the elements in array
return ((query(2 * node, l, mid,
start, end, a)) |
(query(2 * node + 1, mid + 1,
r, start, end, a)));
}
// Function to find the OR sum
static void orsum(int []a, int n,
int q, int []k)
{
// Function to build the segment Tree
build(1, 0, n - 1, a);
// Loop to handle q queries
for(int j = 0; j < q; j++)
{
// Effective number of
// right circular shifts
int i = k[j] % (n / 2);
// Calculating the OR of
// the two halves of the
// array from the segment tree
// OR of second half of the
// array [n/2-i, n-1-i]
int sec = query(1, 0, n - 1,
n / 2 - i,
n - i - 1, a);
// OR of first half of the array
// [n-i, n-1]OR[0, n/2-1-i]
int first = (query(1, 0, n - 1, 0,
n / 2 - 1 - i, a) |
query(1, 0, n - 1,
n - i, n - 1, a));
int temp = sec + first;
// Print readonly answer to the query
Console.Write(temp + "\n");
}
}
// Driver Code
public static void Main(String[] args)
{
int []a = { 7, 44, 19, 86, 65, 39, 75, 101 };
int n = a.Length;
int q = 2;
int []k = { 4, 2 };
orsum(a, n, q, k);
}
}
// This code is contributed by 29AjayKumar
Javascript
238
230
如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live