📌  相关文章
📜  计算乘积模 10^9 + 7 等于 1 的对(1)

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

计算乘积模 10^9 + 7 等于 1 的对

在计算机编程中,我们有时需要计算乘积模某个数的值。本文介绍如何计算乘积模 $10^9 + 7$ 等于 $1$ 的对数。

问题描述

给定 $n$ 个正整数 $a_1, a_2, ..., a_n$,请计算有多少对 $(i, j)$ 使得 $1 \leq i < j \leq n$,且 $a_i \times a_j \equiv 1 \pmod{(10^9 + 7)}$。

解决方案

我们假设 $p = 10^9 + 7$,可以利用费马小定理来求逆元。设 $x$ 是模 $p$ 意义下的一个非零整数,则有:

$$x^{p-1} \equiv 1 \pmod{p}$$

因此,我们可以计算 $a_i$ 的逆元 $b_i$,使得 $a_i \times b_i \equiv 1 \pmod{p}$。具体地,可以使用扩展欧几里得算法求解。假设对于 $a,b \in \mathbb{Z}$,存在一对整数 $x,y$,使得 $ax + by = \operatorname{gcd}(a,b)$,则 $\operatorname{gcd}(a,b)$ 是 $a,b$ 的最大公约数,$x,y$ 是扩展欧几里得算法的一组解。

我们考虑暴力枚举所有的 $(i,j)$,计算 $a_i \times b_j$ 是否等于 $1$,若是则计数器加一。时间复杂度为 $\operatorname{O}(n^2)$,无法通过本题。但是我们可以发现,在计算 $b_i$ 的过程中,我们可以在 $n$ 次操作内求出所有 $b_i$ 的值。因此,我们可以先计算出所有 $b_i$,然后再枚举所有 $(i,j)$,计算 $a_i \times b_j$ 是否等于 $1$。

接下来我们考虑如何优化时间复杂度。对于所有的 $(i,j)$,如果已经计算出 $b_j \times a_i \equiv 1 \pmod{p}$,则可以通过 $(b_j \times a_i) \times b_j \equiv b_j \pmod{p}$ 计算出 $b_j$。因此,我们可以先预处理出所有的 $a_i$,然后将 $a_i$ 与 $b_j$ 的积存储在哈希表中。具体地,对于每个 $a_i$,利用哈希表进行查找,如果能找到 $a_i$ 的逆元,则计数器加上该逆元的出现次数。同时更新哈希表,将 $b_j \times a_i$ 插入哈希表中。

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

代码实现
def solve(n, a):
    mod = 10**9 + 7
    inv = {}
    cnt = 0
    for i in range(n):
        if a[i] in inv:
            cnt += inv[a[i]]
        p = pow(a[i], mod - 2, mod)
        inv[p] = inv.get(p, 0) + 1
        for j in range(i + 1, n):
            if a[j] in inv and (mod + 1 - a[i] * a[j]) % mod in inv:
                cnt += inv[a[j]] * inv[(mod + 1 - a[i] * a[j]) % mod]
            if a[j] * a[i] % mod in inv:
                inv[a[j] * a[i] % mod] += 1
            else:
                inv[a[j] * a[i] % mod] = 1
    return cnt

该算法的时间复杂度为 $\operatorname{O}(n \log n)$,可以通过本题。