Skip to content
Related Articles
Get the best out of our app
GFG App
Open App
geeksforgeeks
Browser
Continue

Related Articles

Range Queries for count of Armstrong numbers in subarray using MO’s algorithm

Improve Article
Save Article
Like Article
Improve Article
Save Article
Like Article

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:

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.  

  1. 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.
  2. 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].
  3. 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


Output: 

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
 


My Personal Notes arrow_drop_up
Last Updated : 25 Apr, 2023
Like Article
Save Article
Similar Reads
Related Tutorials