📌  相关文章
📜  使用 MO 算法对子数组中的阿姆斯特朗数进行范围查询

📅  最后修改于: 2021-09-06 17:45:38             🧑  作者: Mango

给定一个数组arr[]N 个元素和Q 个查询组成,由 L 和 R 表示一个范围,任务是打印子数组[L, R]中阿姆斯特朗数的数量。

例子:

方法:
这个想法是使用 MO 的算法对所有查询进行预处理,以便一个查询的结果可以在下一个查询中使用。

  1. 对所有查询进行排序,将L值从0 到 √n – 1的查询放在一起,然后是从√n 到 2 ×√n – 1 的查询,依此类推。块内的所有查询都按R值的升序排序。
  2. 一一处理所有查询并增加阿姆斯壮数的计数并将结果存储在结构中。
    • 让’ count_Armstrong ‘ 存储前一个查询中阿姆斯特朗数的计数。
    • 删除先前查询的额外元素并为当前查询添加新元素。例如,如果之前的查询是 [0, 8] 而当前的查询是 [3, 9],那么移除元素 arr[0]、arr[1] 和 arr[2] 并添加 arr[9]。
  3. 为了显示结果,请按照提供的顺序对查询进行排序。

添加元素

  • 如果当前元素是 Armstrong 数,则增加count_Armstrong

删除元素

  • 如果当前元素是 Armstrong 数,则递减count_Armstrong

下面是上述方法的实现:

C++
// C++ implementation to count the
// number of Armstrong numbers
// in subarray using MO’s algorithm
 
#include 
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


输出:
4
2










时间复杂度: O(Q * √N)
相关文章:更新数组中 Armstrong 数的范围查询

如果您想与行业专家一起参加直播课程,请参阅Geeks Classes Live