📌  相关文章
📜  给定范围内的数组乘积除数查询|第2组(MO的算法)

📅  最后修改于: 2021-05-19 19:33:56             🧑  作者: Mango

给定大小为NQ[L,R]的查询的数组arr ,任务是查找给定范围内此数组乘积的除数。

先决条件: MO算法,模块化乘法逆,使用筛子的素数分解

例子:

方法:

MO的算法的思想是对所有查询进行预处理,以便一个查询的结果可以在下一个查询中使用。
a [0…n-1]为输入数组, q [0..m-1]为查询数组。

  1. 对所有查询进行排序,将L值从0√n– 1的查询放在一起,然后将所有从√n2×√n– 1的查询放在一起,依此类推。块中的所有查询均按R值的升序排序。
  2. 以每个查询都使用上一个查询中计算出的结果的方式,一个接一个地处理所有查询。令“结果”为先前查询的结果
  3. 数字n可以表示为n = \prod_{i=1}^{n} a_{i}^{p_{i}} ,其中a i是素因子,而p i是它们的整数幂。
    因此,对于该分解,我们有公式可以找到n的除数的总数,即:
  4. 添加函数,我们将计数器数组递增,即counter [a [i]] = counter [a [i]] + p i 。让“ prev”存储counter [a [i]]的先前值。现在,随着计数器数组的更改,结果更改为:
  5. 删除函数,我们将计数器数组递减为counter [a [i]] = counter [a [i]] – p i 。现在,随着计数器数组的更改,结果更改为:

下面是上述方法的实现

// C++ program to Count the divisors 
// of product of an Array in range 
// L to R for Q queries
#include 
using namespace std;
  
#define MAX 1000000
#define MOD 1000000007
#define ll long long int
  
// 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;
};
  
// Store the prime factor of numbers
// till MAX
vector > store[MAX + 1];
  
// Initialized to store the count 
// of prime fators
int counter[MAX + 1] = {};
  
// Result is Initialized to 1
int result = 1;
  
// Inverse array to store
// inverse of number from 1 to MAX
ll inverse[MAX + 1];
  
// 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 to calculate modular
// inverse and storing it in Inverse array
void modularInverse()
{
  
    inverse[0] = inverse[1] = 1;
    for (int i = 2; i <= MAX; i++)
        inverse[i] = inverse[MOD % i]
                    * (MOD - MOD / i) 
                      % MOD;
}
  
// Function to use Sieve to compute
// and store prime numbers
void sieve()
{
  
    store[1].push_back({ 1, 0 });
    for (int i = 2; i <= MAX; i++)
    {
        if (store[i].size() == 0)
        {
            store[i].push_back({ i, 1 });
              
            for (int j = 2 * i; j <= MAX; j += i)
            {
                int cnt = 0;
                int x = j;
                while (x % i == 0)
                    cnt++, x /= i;
                store[j].push_back({ i, cnt });
            }
        }
    }
}
  
// Function to Add elements
// of current range
void add(int currL, int a[])
{
    int value = a[currL];
    for (auto it = store[value].begin();
         it != store[value].end(); it++) {
        // it->first is ai
        // it->second is its integral power
        int prev = counter[it->first];
        counter[it->first] += it->second;
        result = (result * inverse[prev + 1])
                 % MOD;
          
        result = (result *
                  (counter[it->first] + 1))
                  % MOD;
    }
}
  
// Function to remove elements
// of previous range
void remove(int currR, int a[])
{
    int value = a[currR];
    for (auto it = store[value].begin(); 
         it != store[value].end(); it++) {
        // it->first is ai
        // it->second is its integral power
        int prev = counter[it->first];
        counter[it->first] -= it->second;
        result = (result * inverse[prev + 1])
                  % MOD;
        result = (result *
                  (counter[it->first] + 1)) 
                  % MOD;
    }
}
  
// Function to print the answer.
void queryResults(int a[], int n, Query q[],
                  int m)
{
    // 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++;
        }
  
        cout << result << endl;
    }
}
  
// Driver Code
int main()
{
    // Precomputing the prime numbers 
    // using sieve
    sieve();
  
    // Precomputing modular inverse of 
    // numbers from 1 to MAX
    modularInverse();
  
    int a[] = { 5, 2, 3, 1, 4 };
    int n = sizeof(a) / sizeof(a[0]);
      
    Query q[] = { { 1, 3 }, { 0, 4 } };
      
    int m = sizeof(q) / sizeof(q[0]);
      
    // Answer the queries
    queryResults(a, n, q, m);
    return 0;
}
输出:
4
16

时间复杂度: O(Q×sqrt(N))