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++ 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 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 |
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 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# 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