Open In App

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

Last Updated : 25 Apr, 2023
Comments
Improve
Suggest changes
Like Article
Like
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
 


Next Article

Similar Reads