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

📅  最后修改于: 2023-12-03 15:41:17.715000             🧑  作者: Mango

给定范围内的数组乘积除数查询|第2组(MO的算法)

概述

在给定一个数组和多个询问区间的情况下,本算法能够快速地回答所有询问区间的乘积的因子个数之和。

例如,对于数组 [2,3,4,5,6],若询问区间为 [1,3],则该区间内的所有数的乘积为 234=24,其中因子个数为 2,2,3,因子个数之和为 7。

本算法属于在线算法,时间复杂度为 O(n*sqrt(n)),其中 n 为数组长度。可以用于解决许多实际问题,例如 CSDN 讨论区上的这道题

算法流程

本算法采用了 MO 算法的思想,即使用分块技术将查询区间分成若干块,从而达到较好的时间复杂度。

  1. 将所有询问按照左端点所在块和右端点排序。
  2. 当左端点和右端点在同一块时,使用暴力计算该区间内数字的乘积并统计因子个数之和。
  3. 当左端点和右端点不在同一块时,分别计算左端点所在块、右端点所在块和中间所有完整块的乘积。
  4. 统计所有上一步中计算得到的因子个数,即为所求。
代码实现
# 返回一个数的因子个数
def factor_count(n):
    res = 1
    i = 2
    while i * i <= n:
        cnt = 0
        while n % i == 0:
            n /= i
            cnt += 1
        res *= cnt + 1
        i += 1
    if n > 1:
        res *= 2
    return res

# 处理单个询问
def process_query(start, end):
    global result
    cnt = 0
    if block[start] == block[end]:
        for i in range(start, end + 1):
            cnt += factor_count(a[i])
    else:
        for i in range(start, belong[start] * block_size + block_size):
            cnt += factor_count(a[i])
        for i in range(belong[start] + 1, belong[end]):
            cnt += factor_sum[i]
        for i in range(belong[end] * block_size, end + 1):
            cnt += factor_count(a[i])
    result.append(cnt)

# 初始化块信息
def init():
    global factor_sum
    factor_sum = [0] * block_count
    for i in range(block_count):
        start, end = i * block_size, min((i + 1) * block_size, n)
        factor_sum[i] = 0
        for j in range(start, end):
            factor_sum[i] += factor_count(a[j])

# 处理所有询问
def solve():
    global result
    queries.sort(key=lambda q: (belong[q[0]], q[1]))
    result = []
    for query in queries:
        process_query(*query)
    return result

# 测试样例
n = 5
a = [2, 3, 4, 5, 6]
queries = [(1, 3)]
block_size = int(n ** 0.5) + 1
block_count = (n + block_size - 1) // block_size
block = [0] * n
belong = [0] * n
for i in range(n):
    block[i] = i // block_size
    belong[i] = i // block_size
init()
print(solve())  # [7]
总结

本算法使用了分块技术和 MO 算法的思想,可以在 O(n*sqrt(n)) 的时间内处理多个询问。对于一些需要计算因子个数之和的问题,该算法可以帮助程序计算得到答案。