📌  相关文章
📜  查询给定范围内的数字具有的最大除数

📅  最后修改于: 2021-05-04 21:36:58             🧑  作者: Mango

给定Q个查询,其类型为: LR ,对于每个查询,您必须打印数字x(L <= x <= R)所具有的最大除数。
例子:

L = 1 R = 10:
    1 has 1 divisor.
    2 has 2 divisors.
    3 has 2 divisors.
    4 has 3 divisors.
    5 has 2 divisors.
    6 has 4 divisors.
    7 has 2 divisors.
    8 has 4 divisors.
    9 has 3 divisors.
    10 has 4 divisors.

So the answer for above query is 4, as it is the maximum number of 
divisors a number has in [1, 10].

先决条件: Eratosthenes筛网,段树
以下是解决问题的步骤。

  1. 首先,让我们看看一个数n = p 1 k 1 * p 2 k 2 *…* p n k n (其中p 1 ,p 2 ,…,p n是质数)有多少除数;答案是(k 1 +1)*(k 2 +1)* … *(k n +1) 。如何?对于素数分解中的每个素数,我们可以在除数(0,1,2,…,k i )中获得其k i + 1的可能幂。
  2. 现在让我们看看如何找到一个数字的素因式分解,我们首先构建一个数组smallest_prime [] ,该数组存储第i索引中i的最小素数除数,然后将数字除以它的最小素数除以得到一个新的数字(我们还存储了这个新数字的最小质数),直到数字的最小质数改变为止,我们都会一直这样做,当新数字的最小质数因数与先前数字不同时,我们有k i表示给定数的素数分解中的i素数。
  3. 最后,我们获得所有数字的除数的数量,并将它们存储在一个段树中,该树保持段中的最大数。我们通过查询段树来响应每个查询。
C++
// A C++ implementation of the above idea to process
// queries of finding a number with maximum divisors.
#include 
using namespace std;
 
#define maxn 1000005
#define INF 99999999
 
int smallest_prime[maxn];
int divisors[maxn];
int segmentTree[4 * maxn];
 
// Finds smallest prime factor of all numbers in
// range[1, maxn) and stores them in smallest_prime[],
// smallest_prime[i] should contain the smallest prime
// that divides i
void findSmallestPrimeFactors()
{
    // Initialize the smallest_prime factors of all
    // to infinity
    for (int i = 0 ; i < maxn ; i ++ )
        smallest_prime[i] = INF;
 
    // to be built like eratosthenes sieve
    for (long long i = 2; i < maxn; i++)
    {
        if (smallest_prime[i] == INF)
        {
            // prime number will have its smallest_prime
            // equal to itself
            smallest_prime[i] = i;
            for (long long j = i * i; j < maxn; j += i)
 
                // if 'i' is the first prime number reaching 'j'
                if (smallest_prime[j] > i)
                    smallest_prime[j] = i;
        }
    }
}
 
// number of divisors of n = (p1 ^ k1) * (p2 ^ k2) ... (pn ^ kn)
// are equal to (k1+1) * (k2+1) ... (kn+1)
// this function finds the number of divisors of all numbers
// in range [1, maxn) and stores it in divisors[]
// divisors[i] stores the number of divisors i has
void buildDivisorsArray()
{
    for (int i = 1; i < maxn; i++)
    {
        divisors[i] = 1;
        int n = i, p = smallest_prime[i], k = 0;
 
        // we can obtain the prime factorization of the number n
        // n = (p1 ^ k1) * (p2 ^ k2) ... (pn ^ kn) using the
        // smallest_prime[] array, we keep dividing n by its
        // smallest_prime until it becomes 1, whilst we check
        // if we have need to set k zero
        while (n > 1)
        {
            n = n / p;
            k ++;
 
            if (smallest_prime[n] != p)
            {
                //use p^k, initialize k to 0
                divisors[i] = divisors[i] * (k + 1);
                k = 0;
            }
 
            p = smallest_prime[n];
        }
    }
}
 
// builds segment tree for divisors[] array
void buildSegtmentTree(int node, int a, int b)
{
    // leaf node
    if (a == b)
    {
        segmentTree[node] = divisors[a];
        return ;
    }
 
    //build left and right subtree
    buildSegtmentTree(2 * node, a, (a + b) / 2);
    buildSegtmentTree(2 * node + 1, ((a + b) / 2) + 1, b);
 
    //combine the information from left
    //and right subtree at current node
    segmentTree[node] = max(segmentTree[2 * node],
                            segmentTree[2 *node + 1]);
}
 
//returns the maximum number of divisors in [l, r]
int query(int node, int a, int b, int l, int r)
{
    // If current node's range is disjoint with query range
    if (l > b || a > r)
        return -1;
 
    // If the current node stores information for the range
    // that is completely inside the query range
    if (a >= l && b <= r)
        return segmentTree[node];
 
    // Returns maximum number of divisors from left
    // or right subtree
    return max(query(2 * node, a, (a + b) / 2, l, r),
               query(2 * node + 1, ((a + b) / 2) + 1, b,l,r));
}
 
// driver code
int main()
{
    // First find smallest prime divisors for all
    // the numbers
    findSmallestPrimeFactors();
 
    // Then build the divisors[] array to store
    // the number of divisors
    buildDivisorsArray();
 
    // Build segment tree for the divisors[] array
    buildSegtmentTree(1, 1, maxn - 1);
 
    cout << "Maximum divisors that a number has "
         << " in [1, 100] are "
         << query(1, 1, maxn - 1, 1, 100) << endl;
 
 
    cout << "Maximum divisors that a number has"
         << " in [10, 48] are "
         << query(1, 1, maxn - 1, 10, 48) << endl;
 
 
    cout << "Maximum divisors that a number has"
         << " in [1, 10] are "
         << query(1, 1, maxn - 1, 1, 10) << endl;
 
    return 0;
}


Java
// Java implementation of the above idea to process
// queries of finding a number with maximum divisors.
import java.util.*;
 
class GFG
{
static int maxn = 10005;
static int INF = 999999;
 
static int []smallest_prime = new int[maxn];
static int []divisors = new int[maxn];
static int []segmentTree = new int[4 * maxn];
 
// Finds smallest prime factor of all numbers
// in range[1, maxn) and stores them in
// smallest_prime[], smallest_prime[i] should
// contain the smallest prime that divides i
static void findSmallestPrimeFactors()
{
    // Initialize the smallest_prime factors
    // of all to infinity
    for (int i = 0 ; i < maxn ; i ++ )
        smallest_prime[i] = INF;
 
    // to be built like eratosthenes sieve
    for (int i = 2; i < maxn; i++)
    {
        if (smallest_prime[i] == INF)
        {
            // prime number will have its
            // smallest_prime equal to itself
            smallest_prime[i] = i;
            for (int j = i * i; j < maxn; j += i)
 
                // if 'i' is the first
                // prime number reaching 'j'
                if (smallest_prime[j] > i)
                    smallest_prime[j] = i;
        }
    }
}
 
// number of divisors of n = (p1 ^ k1) * (p2 ^ k2) ... (pn ^ kn)
// are equal to (k1+1) * (k2+1) ... (kn+1)
// this function finds the number of divisors of all numbers
// in range [1, maxn) and stores it in divisors[]
// divisors[i] stores the number of divisors i has
static void buildDivisorsArray()
{
    for (int i = 1; i < maxn; i++)
    {
        divisors[i] = 1;
        int n = i, p = smallest_prime[i], k = 0;
 
        // we can obtain the prime factorization of
        // the number n, n = (p1 ^ k1) * (p2 ^ k2) ... (pn ^ kn)
        // using the smallest_prime[] array, we keep dividing n
        // by its smallest_prime until it becomes 1,
        // whilst we check if we have need to set k zero
        while (n > 1)
        {
            n = n / p;
            k ++;
 
            if (smallest_prime[n] != p)
            {
                // use p^k, initialize k to 0
                divisors[i] = divisors[i] * (k + 1);
                k = 0;
            }
            p = smallest_prime[n];
        }
    }
}
 
// builds segment tree for divisors[] array
static void buildSegtmentTree(int node, int a, int b)
{
    // leaf node
    if (a == b)
    {
        segmentTree[node] = divisors[a];
        return ;
    }
 
    //build left and right subtree
    buildSegtmentTree(2 * node, a, (a + b) / 2);
    buildSegtmentTree(2 * node + 1, ((a + b) / 2) + 1, b);
 
    //combine the information from left
    //and right subtree at current node
    segmentTree[node] = Math.max(segmentTree[2 * node],
                                 segmentTree[2 *node + 1]);
}
 
// returns the maximum number of divisors in [l, r]
static int query(int node, int a, int b, int l, int r)
{
    // If current node's range is disjoint
    // with query range
    if (l > b || a > r)
        return -1;
 
    // If the current node stores information
    // for the range that is completely inside
    // the query range
    if (a >= l && b <= r)
        return segmentTree[node];
 
    // Returns maximum number of divisors from left
    // or right subtree
    return Math.max(query(2 * node, a, (a + b) / 2, l, r),
                    query(2 * node + 1,
                         ((a + b) / 2) + 1, b, l, r));
}
 
// Driver Code
public static void main(String[] args)
{
     
    // First find smallest prime divisors
    // for all the numbers
    findSmallestPrimeFactors();
 
    // Then build the divisors[] array to store
    // the number of divisors
    buildDivisorsArray();
 
    // Build segment tree for the divisors[] array
    buildSegtmentTree(1, 1, maxn - 1);
 
    System.out.println("Maximum divisors that a number " +
                       "has in [1, 100] are " +
                        query(1, 1, maxn - 1, 1, 100));
 
 
    System.out.println("Maximum divisors that a number " +
                       "has in [10, 48] are " +
                        query(1, 1, maxn - 1, 10, 48));
 
 
    System.out.println("Maximum divisors that a number " +
                       "has in [1, 10] are " +
                        query(1, 1, maxn - 1, 1, 10));
    }
}
 
// This code is contributed by PrinciRaj1992


Python 3
# Python 3 implementation of the above
# idea to process queries of finding a
# number with maximum divisors.
maxn = 1000005
INF = 99999999
 
smallest_prime = [0] * maxn
divisors = [0] * maxn
segmentTree = [0] * (4 * maxn)
 
# Finds smallest prime factor of all
# numbers in range[1, maxn) and stores
# them in smallest_prime[], smallest_prime[i]
# should contain the smallest prime that divides i
def findSmallestPrimeFactors():
 
    # Initialize the smallest_prime
    # factors of all to infinity
    for i in range(maxn ):
        smallest_prime[i] = INF
 
    # to be built like eratosthenes sieve
    for i in range(2, maxn):
        if (smallest_prime[i] == INF):
             
            # prime number will have its
            # smallest_prime equal to itself
            smallest_prime[i] = i
            for j in range(i * i, maxn , i):
 
                # if 'i' is the first prime
                # number reaching 'j'
                if (smallest_prime[j] > i):
                    smallest_prime[j] = i
 
# number of divisors of n = (p1 ^ k1) *
# (p2 ^ k2) ... (pn ^ kn) are equal to
# (k1+1) * (k2+1) ... (kn+1). This function
# finds the number of divisors of all numbers
# in range [1, maxn) and stores it in divisors[]
# divisors[i] stores the number of divisors i has
def buildDivisorsArray():
    for i in range(1, maxn):
        divisors[i] = 1
        n = i
        p = smallest_prime[i]
        k = 0
 
        # we can obtain the prime factorization
        # of the number n n = (p1 ^ k1) * (p2 ^ k2)
        # ... (pn ^ kn) using the smallest_prime[]
        # array, we keep dividing n by its
        # smallest_prime until it becomes 1, whilst
        # we check if we have need to set k zero
        while (n > 1):
            n = n // p
            k += 1
 
            if (smallest_prime[n] != p):
                 
                # use p^k, initialize k to 0
                divisors[i] = divisors[i] * (k + 1)
                k = 0
 
            p = smallest_prime[n]
 
# builds segment tree for divisors[] array
def buildSegtmentTree( node, a, b):
     
    # leaf node
    if (a == b):
        segmentTree[node] = divisors[a]
        return
 
    #build left and right subtree
    buildSegtmentTree(2 * node, a, (a + b) // 2)
    buildSegtmentTree(2 * node + 1,
                     ((a + b) // 2) + 1, b)
 
    #combine the information from left
    #and right subtree at current node
    segmentTree[node] = max(segmentTree[2 * node],
                            segmentTree[2 * node + 1])
 
# returns the maximum number of
# divisors in [l, r]
def query(node, a, b, l, r):
     
    # If current node's range is disjoint
    # with query range
    if (l > b or a > r):
        return -1
 
    # If the current node stores information
    # for the range that is completely inside
    # the query range
    if (a >= l and b <= r):
        return segmentTree[node]
 
    # Returns maximum number of divisors
    # from left or right subtree
    return max(query(2 * node, a, (a + b) // 2, l, r),
               query(2 * node + 1,
                    ((a + b) // 2) + 1, b, l, r))
 
# Driver code
if __name__ == "__main__":
     
    # First find smallest prime divisors
    # for all the numbers
    findSmallestPrimeFactors()
 
    # Then build the divisors[] array to
    # store the number of divisors
    buildDivisorsArray()
 
    # Build segment tree for the divisors[] array
    buildSegtmentTree(1, 1, maxn - 1)
    print("Maximum divisors that a number has ",
                            " in [1, 100] are ",
                  query(1, 1, maxn - 1, 1, 100))
 
    print("Maximum divisors that a number has",
                           " in [10, 48] are ",
                 query(1, 1, maxn - 1, 10, 48))
 
 
    print( "Maximum divisors that a number has",
                             " in [1, 10] are ",
                   query(1, 1, maxn - 1, 1, 10))
 
# This code is contributed by ita_c


C#
// C# implementation of the above idea
// to process queries of finding a number
// with maximum divisors.
using System;
     
class GFG
{
static int maxn = 10005;
static int INF = 999999;
 
static int []smallest_prime = new int[maxn];
static int []divisors = new int[maxn];
static int []segmentTree = new int[4 * maxn];
 
// Finds smallest prime factor of all numbers
// in range[1, maxn) and stores them in
// smallest_prime[], smallest_prime[i] should
// contain the smallest prime that divides i
static void findSmallestPrimeFactors()
{
    // Initialize the smallest_prime
    // factors of all to infinity
    for (int i = 0 ; i < maxn ; i ++ )
        smallest_prime[i] = INF;
 
    // to be built like eratosthenes sieve
    for (int i = 2; i < maxn; i++)
    {
        if (smallest_prime[i] == INF)
        {
            // prime number will have its
            // smallest_prime equal to itself
            smallest_prime[i] = i;
            for (int j = i * i; j < maxn; j += i)
 
                // if 'i' is the first
                // prime number reaching 'j'
                if (smallest_prime[j] > i)
                    smallest_prime[j] = i;
        }
    }
}
 
// number of divisors of
// n = (p1 ^ k1) * (p2 ^ k2) ... (pn ^ kn)
// are equal to (k1+1) * (k2+1) ... (kn+1)
// this function finds the number of divisors
// of all numbers in range [1, maxn) and stores
// it in divisors[] divisors[i] stores the
// number of divisors i has
static void buildDivisorsArray()
{
    for (int i = 1; i < maxn; i++)
    {
        divisors[i] = 1;
        int n = i, p = smallest_prime[i], k = 0;
 
        // we can obtain the prime factorization of
        // the number n,
        // n = (p1 ^ k1) * (p2 ^ k2) ... (pn ^ kn)
        // using the smallest_prime[] array,
        // we keep dividing n by its smallest_prime
        // until it becomes 1, whilst we check if
        // we have need to set k zero
        while (n > 1)
        {
            n = n / p;
            k ++;
 
            if (smallest_prime[n] != p)
            {
                // use p^k, initialize k to 0
                divisors[i] = divisors[i] * (k + 1);
                k = 0;
            }
            p = smallest_prime[n];
        }
    }
}
 
// builds segment tree for divisors[] array
static void buildSegtmentTree(int node,
                              int a, int b)
{
    // leaf node
    if (a == b)
    {
        segmentTree[node] = divisors[a];
        return;
    }
 
    //build left and right subtree
    buildSegtmentTree(2 * node, a, (a + b) / 2);
    buildSegtmentTree(2 * node + 1,
                    ((a + b) / 2) + 1, b);
 
    //combine the information from left
    //and right subtree at current node
    segmentTree[node] = Math.Max(segmentTree[2 * node],
                                 segmentTree[2 *node + 1]);
}
 
// returns the maximum number of divisors in [l, r]
static int query(int node, int a, int b, int l, int r)
{
    // If current node's range is disjoint
    // with query range
    if (l > b || a > r)
        return -1;
 
    // If the current node stores information
    // for the range that is completely inside
    // the query range
    if (a >= l && b <= r)
        return segmentTree[node];
 
    // Returns maximum number of divisors from left
    // or right subtree
    return Math.Max(query(2 * node, a, (a + b) / 2, l, r),
                    query(2 * node + 1,
                        ((a + b) / 2) + 1, b, l, r));
}
 
// Driver Code
public static void Main(String[] args)
{
     
    // First find smallest prime divisors
    // for all the numbers
    findSmallestPrimeFactors();
 
    // Then build the divisors[] array
    // to store the number of divisors
    buildDivisorsArray();
 
    // Build segment tree for the divisors[] array
    buildSegtmentTree(1, 1, maxn - 1);
 
    Console.WriteLine("Maximum divisors that a number " +
                                 "has in [1, 100] are " +
                          query(1, 1, maxn - 1, 1, 100));
 
    Console.WriteLine("Maximum divisors that a number " +
                                 "has in [10, 48] are " +
                          query(1, 1, maxn - 1, 10, 48));
 
    Console.WriteLine("Maximum divisors that a number " +
                                  "has in [1, 10] are " +
                           query(1, 1, maxn - 1, 1, 10));
    }
}
 
// This code is contributed by 29AjayKumar


Javascript


输出:

Maximum divisors that a number has in [1, 100] are 12
Maximum divisors that a number has in [10, 48] are 10
Maximum divisors that a number has in [1, 10] are 4

时间复杂度:

For sieve: O(maxn * log(log(maxn)) )
For calculating divisors of each number: O(k1 + k2 + ... + kn) < O(log(maxn))
For querying each range: O(log(maxn))
Total: O((maxn + Q) * log(maxn))