📌  相关文章
📜  计算数组中的对,使得 LCM(arr[i], arr[j]) > min(arr[i],arr[j])(1)

📅  最后修改于: 2023-12-03 14:57:31.213000             🧑  作者: Mango

计算数组中的对,使得 LCM(arr[i], arr[j]) > min(arr[i],arr[j])

这个问题可以通过暴力枚举数组中所有可能的数对来解决,但是时间复杂度为 $O(n^2)$,对于数据量较大的情况可能会超时。

下面介绍一种时间复杂度为 $O(n\log n)$ 的解法。

我们先来解决一个比较简单的问题:如何快速计算数组中所有数对的 LCM 和 min 值。

设 $LCM(i,j)$ 表示数组中 $i$ 和 $j$ 的 LCM 值,$min(i,j)$ 表示数组中 $i$ 和 $j$ 的最小值,那么有:

$$LCM(i,j) = \frac{arr[i] \times arr[j]}{gcd(arr[i], arr[j])}$$

$$min(i,j) = \min{arr[i], arr[j]}$$

其中 $gcd$ 表示最大公约数,可以使用欧几里得算法来计算,时间复杂度为 $O(\log n)$。

接着我们考虑如何利用以上方法求解本题。注意到对于一个数对 $(i,j)$,如果满足条件 LCM($i,j$) > min($i,j$),那么意味着 $\frac{arr[i]}{gcd(arr[i], arr[j])} \neq \frac{arr[j]}{gcd(arr[i], arr[j])}$,否则它们的 LCM 和 min 值相同。因此我们可以枚举一个数 $i$,然后找到所有满足上述条件的 $j$,这些 $j$ 的下标就构成了一些对。我们可以使用一个哈希表来存储每个值出现的下标,然后在查找时可以快速定位。

下面是 Python 代码实现:

from math import gcd

def count_pairs(arr):
    n = len(arr)
    count = 0
    hash_table = {}  # 存储每个值出现的下标
    for i in range(n):
        # 枚举数对 (i,j)
        for j in range(i+1, n):
            # 计算 LCM 和 min 值
            lcm = arr[i] * arr[j] // gcd(arr[i], arr[j])
            min_val = min(arr[i], arr[j])
            # 检查是否满足条件
            if lcm > min_val:
                count += 1
                # 将 i 和 j 加入哈希表
                if arr[i] in hash_table:
                    hash_table[arr[i]].append(i)
                else:
                    hash_table[arr[i]] = [i]
                if arr[j] in hash_table:
                    hash_table[arr[j]].append(j)
                else:
                    hash_table[arr[j]] = [j]
    # 枚举每个数 i,查找符合条件的 j
    for i in range(n):
        for j in hash_table:
            if j == arr[i]:
                continue
            lcm = arr[i] * j // gcd(arr[i], j)
            if lcm > arr[i]:
                # 计算在哈希表中出现的次数
                count += len([x for x in hash_table[j] if x > i])
    return count

时间复杂度为 $O(n\log n)$。