📅  最后修改于: 2023-12-03 15:36:47.202000             🧑  作者: Mango
本题给出一个长度为 $n$ 的整数序列,统计其中乘积为两个整数的平方差的子序列数。
例如,对于序列 [3, 1, 4, 6, 5],其中乘积为两个整数的平方差的子序列有:
因此,答案为 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;
}