📌  相关文章
📜  其乘积为两个整数的平方差的子序列数(1)

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

介绍题目

本题给出一个长度为 $n$ 的整数序列,统计其中乘积为两个整数的平方差的子序列数。

例如,对于序列 [3, 1, 4, 6, 5],其中乘积为两个整数的平方差的子序列有:

  • [3, 4, 5],乘积为 60,是 $2^2 - 1^2$。
  • [4, 5],乘积为 20,是 $2^2 - (-1)^2$。

因此,答案为 2。

解题思路

考虑对每个数 $x$,将其因数分解后,分别记录平方数和非平方数的个数,设分别为 $cnt_1$ 和 $cnt_2$。则以 $x$ 结尾的序列中,乘积为两个整数的平方差的子序列数为 $cnt_1 \times cnt_2$。这个结果可以从一个桶中得到,桶的下标为差值,值为子序列数。

因此,我们可以遍历序列,对每个数进行因数分解,并更新答案。为了防止重复(一个数被分解多次),我们需要在记录因数的时候,只记录一个等效的质因数即可。

具体实现时,可以使用 unordered_map 来记录桶。

代码实现

int solve(vector<int>& nums) {
    int n = nums.size(), ans = 0;

    for (int i = 1; i < n; i++) {
        unordered_map<int, int> cnt;
        for (int j = i-1; j >= 0; j--) {
            int x = nums[j], y = nums[i];

            int d = gcd(x, y);
            if (d != 1) {
                x /= d; y /= d;
            }

            if (x == 1 || y == 1) continue;   // 跳过重复的数

            if ((x*y) % (x*x - y*y) == 0) {
                int delta = (x*y) / (x*x - y*y);
                if (cnt.count(delta)) ans += cnt[delta];
            }

            // 更新桶
            if (x % d == 0 && y % d == 0) {
                cnt[y/x]++;
            }
        }
    }

    return ans;
}

返回的 markdown 格式如下:

# 介绍题目
本题给出一个长度为 $n$ 的整数序列,统计其中乘积为两个整数的平方差的子序列数。

例如,对于序列 [3, 1, 4, 6, 5],其中乘积为两个整数的平方差的子序列有:
- [3, 4, 5],乘积为 60,是 $2^2 - 1^2$。
- [4, 5],乘积为 20,是 $2^2 - (-1)^2$。

因此,答案为 2。

# 解题思路
考虑对每个数 $x$,将其因数分解后,分别记录平方数和非平方数的个数,设分别为 $cnt_1$ 和 $cnt_2$。则以 $x$ 结尾的序列中,乘积为两个整数的平方差的子序列数为 $cnt_1 \times cnt_2$。这个结果可以从一个桶中得到,桶的下标为差值,值为子序列数。

因此,我们可以遍历序列,对每个数进行因数分解,并更新答案。为了防止重复(一个数被分解多次),我们需要在记录因数的时候,只记录一个等效的质因数即可。

具体实现时,可以使用 unordered_map 来记录桶。

# 代码实现
```c++
int solve(vector<int>& nums) {
    int n = nums.size(), ans = 0;

    for (int i = 1; i < n; i++) {
        unordered_map<int, int> cnt;
        for (int j = i-1; j >= 0; j--) {
            int x = nums[j], y = nums[i];

            int d = gcd(x, y);
            if (d != 1) {
                x /= d; y /= d;
            }

            if (x == 1 || y == 1) continue;   // 跳过重复的数

            if ((x*y) % (x*x - y*y) == 0) {
                int delta = (x*y) / (x*x - y*y);
                if (cnt.count(delta)) ans += cnt[delta];
            }

            // 更新桶
            if (x % d == 0 && y % d == 0) {
                cnt[y/x]++;
            }
        }
    }

    return ans;
}