给定N个元素的数组arr [] ,任务是回答Q个查询,每个查询都有两个整数L和R。对于每个查询,任务是找到数字总和为偶数的子数组arr [L…R]中的元素数量。
例子:
Input:arr[] = {7, 3, 19, 13, 5, 4}
query = { {1, 5}, {0, 1} }
Output: 3
Explanation:
Query 1: Elements 19, 13 and 4 have even digit sum in the subarray: {3, 9, 13, 5, 4}.
Query 2: No elements have even sum in the subarray: {7, 3}
Input:arr[] = {0, 1, 2, 3, 4, 5, 6, 7}
query = { 3, 5 }
Output:1
我们已经讨论了这种方法:使用段树查询给定范围内的偶数和元素的计数
方法:(使用MO的算法)
这个想法是预处理所有查询,以便一个查询的结果可以在下一个查询中使用。
- 对所有查询进行排序,将L值从0到√n– 1的查询放在一起,然后是从√n到2×√n– 1的查询,依此类推。块中的所有查询均按R值的升序排序。
- 一个接一个地处理所有查询,并增加偶数和元素的数量,并将结果存储在结构中。
- 让count_even存储上一个查询中的偶数和元素的计数。
- 删除先前查询的多余元素,并为当前查询添加新元素。例如,如果上一个查询为[0,8],而当前查询为[3,9],则删除元素arr [0],arr [1]和arr [2]并添加arr [9]。
- 为了显示结果,请按查询顺序对查询进行排序。
Helper functions:
Adding elements()
- If the current element has even digit sum then increase the count of count_even.
Removing elements()
- If the current element has even digit sum then decrease the count of count_even.
下面的代码是上述方法的实现:
C++
// C++ program to count of even
// digit sum elements in the given
// range using MO's algorithm
#include
using namespace std;
#define MAX 100000
// Variable to represent block size.
// This is made global so compare()
// of sort can use it.
int block;
// Structure to represent a query range
struct Query {
// Starting index
int L;
// Ending index
int R;
// Index of query
int index;
// Count of even
// even digit sum
int even;
};
// To store the count of
// even digit sum
int count_even;
// Function used to sort all queries so that
// all queries of the same block are arranged
// together and within a block, queries are
// sorted in increasing order of R values.
bool compare(Query x, Query y)
{
// Different blocks, sort by block.
if (x.L / block != y.L / block)
return x.L / block < y.L / block;
// Same block, sort by R value
return x.R < y.R;
}
// Function used to sort all queries
// in order of their index value so that
// results of queries can be printed
// in same order as of input
bool compare1(Query x, Query y)
{
return x.index < y.index;
}
// Function to find the digit sum
// for a number
int digitSum(int num)
{
int sum = 0;
while (num) {
sum += (num % 10);
num /= 10;
}
return sum;
}
// Function to Add elements
// of current range
void add(int currL, int a[])
{
// If digit sum of a[currL]
// is even then increment
if (digitSum(a[currL]) % 2 == 0)
count_even++;
}
// Function to remove elements
// of previous range
void remove(int currR, int a[])
{
// If digit sum of a[currL]
// is even then decrement
if (digitSum(a[currR]) % 2 == 0)
count_even--;
}
// Function to generate
// the result of queries
void queryResults(int a[], int n,
Query q[], int m)
{
// Initialize number of
// even digit sum to 0
count_even = 0;
// Find block size
block = (int)sqrt(n);
// Sort all queries so that queries of
// same blocks are arranged together.
sort(q, q + m, compare);
// Initialize current L, current R and
// current result
int currL = 0, currR = 0;
for (int i = 0; i < m; i++) {
// L and R values of current range
int L = q[i].L, R = q[i].R;
// Add Elements of current range
while (currR <= R) {
add(currR, a);
currR++;
}
while (currL > L) {
add(currL - 1, a);
currL--;
}
// Remove element of previous range
while (currR > R + 1)
{
remove(currR - 1, a);
currR--;
}
while (currL < L) {
remove(currL, a);
currL++;
}
q[i].even = count_even;
}
}
// Function to display the results of
// queries in their initial order
void printResults(Query q[], int m)
{
sort(q, q + m, compare1);
for (int i = 0; i < m; i++) {
cout << q[i].even << endl;
}
}
// Driver Code
int main()
{
int arr[] = { 5, 2, 3, 1, 4, 8, 10, 12 };
int n = sizeof(arr) / sizeof(arr[0]);
Query q[] = { { 1, 3, 0, 0 },
{ 0, 4, 1, 0 },
{ 4, 7, 2, 0 } };
int m = sizeof(q) / sizeof(q[0]);
queryResults(arr, n, q, m);
printResults(q, m);
return 0;
}
Java
// Java program to count of even
// digit sum elements in the given
// range using MO's algorithm
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
class GFG{
static int MAX = 100000;
// Variable to represent block size.
// This is made global so compare()
// of sort can use it.
static int block;
// Structure to represent a query range
static class Query
{
// Starting index
int L;
// Ending index
int R;
// Index of query
int index;
// Count of even
// even digit sum
int even;
public Query(int l, int r,
int index, int even)
{
this.L = l;
this.R = r;
this.index = index;
this.even = even;
}
};
// To store the count of
// even digit sum
static int count_even;
// Function to find the digit sum
// for a number
static int digitSum(int num)
{
int sum = 0;
while (num > 0)
{
sum += (num % 10);
num /= 10;
}
return sum;
}
// Function to Add elements
// of current range
static void add(int currL, int a[])
{
// If digit sum of a[currL]
// is even then increment
if (digitSum(a[currL]) % 2 == 0)
count_even++;
}
// Function to remove elements
// of previous range
static void remove(int currR, int a[])
{
// If digit sum of a[currL]
// is even then decrement
if (digitSum(a[currR]) % 2 == 0)
count_even--;
}
// Function to generate
// the result of queries
static void queryResults(int a[], int n,
Query q[], int m)
{
// Initialize number of
// even digit sum to 0
count_even = 0;
// Find block size
block = (int) Math.sqrt(n);
// Sort all queries so that queries of
// same blocks are arranged together.
Collections.sort(Arrays.asList(q),
new Comparator()
{
// Function used to sort all queries so that
// all queries of the same block are arranged
// together and within a block, queries are
// sorted in increasing order of R values.
public int compare(Query x, Query y)
{
// Different blocks, sort by block.
if (x.L / block != y.L / block)
return x.L / block - y.L / block;
// Same block, sort by R value
return x.R - y.R;
}
});
// Initialize current L, current R and
// current result
int currL = 0, currR = 0;
for(int i = 0; i < m; i++)
{
// L and R values of current range
int L = q[i].L, R = q[i].R;
// Add Elements of current range
while (currR <= R)
{
add(currR, a);
currR++;
}
while (currL > L)
{
add(currL - 1, a);
currL--;
}
// Remove element of previous range
while (currR > R + 1)
{
remove(currR - 1, a);
currR--;
}
while (currL < L)
{
remove(currL, a);
currL++;
}
q[i].even = count_even;
}
}
// Function to display the results of
// queries in their initial order
static void printResults(Query q[], int m)
{
Collections.sort(Arrays.asList(q),
new Comparator()
{
// Function used to sort all queries
// in order of their index value so that
// results of queries can be printed
// in same order as of input
public int compare(Query x, Query y)
{
return x.index - y.index;
}
});
for(int i = 0; i < m; i++)
{
System.out.println(q[i].even);
}
}
// Driver Code
public static void main(String[] args)
{
int arr[] = { 5, 2, 3, 1, 4, 8, 10, 12 };
int n = arr.length;
Query q[] = { new Query(1, 3, 0, 0),
new Query(0, 4, 1, 0),
new Query(4, 7, 2, 0) };
int m = q.length;
queryResults(arr, n, q, m);
printResults(q, m);
}
}
// This code is contributed by sanjeev2552
输出:
1
2
2
时间复杂度: O(Q x√N)