Range Queries for count of Armstrong numbers in subarray using MO’s algorithm
Given an array arr[] consisting of N elements and Q queries represented by L and R denoting a range, the task is to print the number of Armstrong numbers in the subarray [L, R].
Examples:
Input: arr[] = {18, 153, 8, 9, 14, 5}
Query 1: query(L=0, R=5)
Query 2: query(L=3, R=5)
Output: 4
2
Explanation:
18 => 1*1 + 8*8 != 18
153 => 1*1*1 + 5*5*5 + 3*3*3 = 153
8 => 8 = 8
9 => 9 = 9
14 => 1*1 + 4*4 != 14
Query 1: The subarray[0…5] has 4 Armstrong numbers viz. {153, 8, 9, 5}
Query 2: The subarray[3…5] has 2 Armstrong numbers viz. {9, 5}
Approach:
The idea is to use MO’s algorithm to pre-process all queries so that result of one query can be used in the next query.
- Sort all queries in a way that queries with L values from 0 to √n – 1 are put together, followed by queries from √n to 2 ×√n – 1, and so on. All queries within a block are sorted in increasing order of R values.
- Process all queries one by one and increase the count of Armstrong numbers and store the result in the structure.
- Let ‘count_Armstrong‘ store the count of Armstrong numbers in the previous query.
- Remove extra elements of previous query and add new elements for the current query. For example, if previous query was [0, 8] and the current query is [3, 9], then remove the elements arr[0], arr[1] and arr[2] and add arr[9].
- In order to display the results, sort the queries in the order they were provided.
Adding elements
- If the current element is a Armstrong number then increment count_Armstrong.
Removing elements
- If the current element is a Armstrong number then decrement count_Armstrong.
Below is the implementation of the above approach:
C++
// C++ implementation to count the // number of Armstrong numbers // in subarray using MO’s algorithm #include <bits/stdc++.h> using namespace std; // 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 { int L, R, index; // Count of Armstrong // numbers int armstrong; }; // To store the count of // Armstrong numbers int count_Armstrong; // 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 that return true // if num is armstrong // else return false bool isArmstrong( int x) { int n = to_string(x).size(); int sum1 = 0; int temp = x; while (temp > 0) { int digit = temp % 10; sum1 += pow (digit, n); temp /= 10; } if (sum1 == x) return true ; return false ; } // Function to Add elements // of current range void add( int currL, int a[]) { // If a[currL] is a Armstrong number // then increment count_Armstrong if (isArmstrong(a[currL])) count_Armstrong++; } // Function to remove elements // of previous range void remove ( int currR, int a[]) { // If a[currL] is a Armstrong number // then decrement count_Armstrong if (isArmstrong(a[currR])) count_Armstrong--; } // Function to generate the result of queries void queryResults( int a[], int n, Query q[], int m) { // Initialize count_Armstrong to 0 count_Armstrong = 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].armstrong = count_Armstrong; } } // 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].armstrong << endl; } } // Driver Code int main() { int arr[] = { 18, 153, 8, 9, 14, 5 }; int n = sizeof (arr) / sizeof (arr[0]); Query q[] = { { 0, 5, 0, 0 }, { 3, 5, 1, 0 } }; int m = sizeof (q) / sizeof (q[0]); queryResults(arr, n, q, m); printResults(q, m); return 0; } |
Java
// Java implementation to count the // number of Armstrong numbers // in subarray using MO’s algorithm import java.io.*; import java.util.*; // Class to represent // a query range class Query { int L, R, index; // Count of Armstrong // numbers int armstrong; Query( int L, int R, int index, int armstrong) { this .L = L; this .R = R; this .index = index; this .armstrong = armstrong; } } class GFG{ // Variable to represent block size. static int block; // To store the count of // Armstrong numbers static int count_Armstrong; // Function that return true // if num is armstrong // else return false static boolean isArmstrong( int x) { int n = String.valueOf(x).length(); int sum1 = 0 ; int temp = x; while (temp > 0 ) { int digit = temp % 10 ; sum1 += Math.pow(digit, n); temp /= 10 ; } if (sum1 == x) return true ; return false ; } // Function to Add elements // of current range static void add( int currL, int a[]) { // If a[currL] is a Armstrong number // then increment count_Armstrong if (isArmstrong(a[currL])) count_Armstrong++; } // Function to remove elements // of previous range static void remove( int currR, int a[]) { // If a[currL] is a Armstrong number // then decrement count_Armstrong if (isArmstrong(a[currR])) count_Armstrong--; } // Function to generate the result of queries static void queryResults( int a[], int n, Query q[], int m) { // Initialize count_Armstrong to 0 count_Armstrong = 0 ; // Find block size block = ( int )(Math.sqrt(n)); // 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. Arrays.sort(q, (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].armstrong = count_Armstrong; } } // Function to display the results of // queries in their initial order static void printResults(Query q[], int m) { Arrays.sort(q, (Query x, Query y) -> // sort all queries // in order of their // index value so that results // of queries can be printed // in same order as of input); x.index - y.index); for ( int i = 0 ; i < m; i++) { System.out.println(q[i].armstrong); } } // Driver Code public static void main(String[] args) { int arr[] = { 18 , 153 , 8 , 9 , 14 , 5 }; int n = arr.length; Query q[] = new Query[ 2 ]; q[ 0 ] = new Query( 0 , 5 , 0 , 0 ); q[ 1 ] = new Query( 3 , 5 , 1 , 0 ); int m = q.length; queryResults(arr, n, q, m); printResults(q, m); } } // This code is contributed by jithin |
Python3
import math block = 0 # Structure to represent a query range class Query: def __init__( self , L, R, index): self .L = L self .R = R self .index = index self .armstrong = 0 # To store the count of Armstrong numbers count_Armstrong = 0 # 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. def compare(x, 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 the same order as input def compare1(x, y): return x.index < y.index # Function that returns True # if num is an Armstrong number # else returns False def isArmstrong(x): n = len ( str (x)) sum1 = 0 temp = x while temp > 0 : digit = temp % 10 sum1 + = pow (digit, n) temp / / = 10 if sum1 = = x: return True return False # Function to add elements of current range def add(currL, a): global count_Armstrong # If a[currL] is an Armstrong number, # then increment count_Armstrong if isArmstrong(a[currL]): count_Armstrong + = 1 # Function to remove elements of previous range def remove(currR, a): global count_Armstrong # If a[currL] is an Armstrong number, # then decrement count_Armstrong if isArmstrong(a[currR]): count_Armstrong - = 1 def queryResults(a, n, q, m): global block global count_Armstrong # Initialize count_Armstrong to 0 count_Armstrong = 0 block = int (math.sqrt(n)) # Sort all queries so that queries of # same blocks are arranged together. q.sort(key = lambda x: (x.L / / block, x.R)) currL = 0 currR = 0 for i in range (m): L = q[i].L R = q[i].R # Add Elements of current range while currR < = R: add(currR, a) currR + = 1 while currL > L: add(currL - 1 , a) currL - = 1 while currR > R + 1 : remove(currR - 1 , a) currR - = 1 while currL < L: remove(currL, a) currL + = 1 # Create a new Query object with the results and add it to the list q[i].armstrong = count_Armstrong # Function to display the results of # queries in their initial order def printResults(q, m): q.sort(key = lambda x: x.index) for i in range (m): print (q[i].armstrong) if __name__ = = '__main__' : arr = [ 18 , 153 , 8 , 9 , 14 , 5 ] n = len (arr) q = [Query( 0 , 5 , 0 ), Query( 3 , 5 , 1 )] m = len (q) queryResults(arr, n, q, m) printResults(q, m) #Contributed by Aditya Sharma |
Javascript
// Javascript implementation to count the // number of Armstrong numbers // in subarray using MO’s algorithm // Variable to represent block size. // This is made global so compare() // of sort can use it. let block; let count_Armstrong; // Structure to represent // a query range function Query(L, R, index, armstrong) { this .L = L; this .R = R; this .index = index; // Count of Armstrong // numbers this .armstrong = armstrong; } // 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. function compare(x, y) { // Different blocks, sort by block. if (Math.floor(x.L / block) !== Math.floor(y.L / block)) { return Math.floor(x.L / block) - Math.floor(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 function compare1(x, y) { return x.index - y.index; } // Function that return true // if num is armstrong // else return false function isArmstrong(x) { let n = x.toString().length; let sum1 = 0; let temp = x; while (temp > 0) { let digit = temp % 10; sum1 += Math.pow(digit, n); temp = Math.floor(temp / 10); } return sum1 === x; } // Function to Add elements // of current range function add(currL, a) { // If a[currL] is a Armstrong number // then increment count_Armstrong if (isArmstrong(a[currL])) { count_Armstrong++; } } function remove(currR, a) { // If a[currL] is a Armstrong number // then decrement count_Armstrong if (isArmstrong(a[currR])) { count_Armstrong--; } } // Function to generate the result of queries function queryResults(a, n, q, m) { // Initialize count_Armstrong to 0 count_Armstrong = 0; block = Math.floor(Math.sqrt(n)); // Sort all queries so that queries of // same blocks are arranged together. q.sort(compare); let currL = 0, currR = 0; for (let i = 0; i < m; i++) { // L and R values of current range let 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].armstrong = count_Armstrong; } } // Function to display the results of // queries in their initial order function printResults(q, m) { q.sort(compare1); for (let i = 0; i < m; i++) { console.log(q[i].armstrong); } } // Driver Code const arr = [18, 153, 8, 9, 14, 5]; const n = arr.length; const q = [ new Query(0, 5, 0, 0), new Query(3, 5, 1, 0) ]; const m = q.length; queryResults(arr, n, q, m); printResults(q, m); // This code is contributed by princekumaras |
C#
// C# implementation to count the // number of Armstrong numbers // in subarray using MO’s algorithm using System; using System.Collections.Generic; using System.Linq; // Class to represent // a query range class Query { // Count of Armstrong // numbers public int L, R, index, armstrong; public Query( int L, int R, int index, int armstrong) { this .L = L; this .R = R; this .index = index; this .armstrong = armstrong; } } class GFG { // Variable to represent block size. static int block; // To store the count of // Armstrong numbers static int count_Armstrong; // Function that return true // if num is armstrong // else return false static bool isArmstrong( int x) { int n = x.ToString().Length; int sum1 = 0; int temp = x; while (temp > 0) { int digit = temp % 10; sum1 += ( int )Math.Pow(digit, n); temp /= 10; } if (sum1 == x) return true ; return false ; } // Function to Add elements // of current range static void add( int currL, int [] a) { // If a[currL] is a Armstrong number // then increment count_Armstrong if (isArmstrong(a[currL])) count_Armstrong++; } // Function to remove elements // of previous range static void remove( int currR, int [] a) { // If a[currL] is a Armstrong number // then decrement count_Armstrong if (isArmstrong(a[currR])) count_Armstrong--; } // Function to generate the result of queries static void queryResults( int [] a, int n, Query[] q, int m) { // Initialize count_Armstrong to 0 count_Armstrong = 0; // Find block size block = ( int )(Math.Sqrt(n)); // 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. Array.Sort(q, (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].armstrong = count_Armstrong; } } // Function to display the results of // queries in their initial order static void printResults(Query[] q, int m) { Array.Sort(q, (Query x, Query y) => // sort all queries // in order of their // index value so that results // of queries can be printed // in same order as of input); x.index - y.index); for ( int i = 0; i < m; i++) { Console.WriteLine(q[i].armstrong); } } // Driver code static void Main( string [] args) { int [] arr = { 18, 153, 8, 9, 14, 5 }; int n = arr.Length; Query[] q = new Query[2]; q[0] = new Query(0, 5, 0, 0); q[1] = new Query(3, 5, 1, 0); int m = q.Length; queryResults(arr, n, q, m); printResults(q, m); } } // This code is contributed adityashatmfh |
4 2
Time Complexity: O((Q*log(Q)+Q * √N)
Auxiliary Space: O(1)
Related article: Range Queries for number of Armstrong numbers in an array with updates
Please Login to comment...