Open In App

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

Improve
Improve
Like Article
Like
Save
Share
Report

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
 



Last Updated : 25 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads