📅  最后修改于: 2023-12-03 15:36:02.111000             🧑  作者: Mango
给定一个整数序列 $a_1, a_2,\dots, a_n$,请计算其中有多少子序列乘积为两个整数的平方差,即 $a_i\times a_j = k^2\pm 1$($i<j$,$k$ 是一个整数)。
我们可以对于每一个满足 $a_i\times a_j = k^2\pm 1$ 的 $(i,j,k)$,都记下以 $a_i$ 为第一个数,$a_j$ 为第二个数的子序列数。最后将所有的子序列数相加即可。
需要注意的是,若 $a_i$ 和 $a_j$ 均大于 $1$,那么 $a_i$ 和 $a_j$ 中一定有一个数是奇数,一个数是偶数。因此可以对于每个奇数 $x$,统计出序列中有多少偶数满足 $x\times a_j = k^2\pm 1$;对于每个偶数 $x$,统计出序列中有多少奇数满足 $x\times a_j = k^2\pm 1$。
这个做法的时间复杂度为 $O(n^2\log n)$,可以通过 50 分的测试点。
我们仔细分析一下这个问题。设 $\Delta=a_i-a_j$,则 $a_i-a_j = \frac{k^2-1}{a_i+a_j}$,因此 $a_i+a_j$ 一定是 $\Delta$ 的因子。
我们可以对于每个 $i$,考虑 $a_i$ 的因子有哪些,然后枚举 $\Delta$ 找到 $j$,统计个数。需要注意的是 $a_i=a_j$ 的情况。
这个做法的时间复杂度为 $O(n\sqrt{a_n})$,可以通过本题。
思路一的参考代码:
n = int(input())
a = list(map(int, input().split()))
ans = 0
for i in range(n):
cnt_odd = {1: 1}
cnt_even = {}
for j in range(i+1, n):
if a[j] % 2 == 0:
if cnt_odd.get(a[j]//2):
ans += cnt_odd[a[j]//2]
if cnt_even.get(a[j]//2):
ans += cnt_even[a[j]//2]
cnt_even[a[j]] = cnt_even.get(a[j], 0) + 1
else:
if cnt_even.get((a[j]-1)//2):
ans += cnt_even[(a[j]-1)//2]
if cnt_odd.get((a[j]-1)//2):
ans += cnt_odd[(a[j]-1)//2]
cnt_odd[a[j]] = cnt_odd.get(a[j], 0) + 1
print(ans)
思路二的参考代码:
n = int(input())
a = list(map(int, input().split()))
ans = 0
for i in range(n):
cnt = {}
for j in range(i+1, n):
delta = a[i] - a[j]
if delta == 0:
ans += 1
else:
divisor = 1
while divisor * divisor <= delta:
if delta % divisor == 0:
if cnt.get(divisor) is not None and a[i] * a[j] == divisor * divisor + a[i] * a[j] // divisor:
ans += cnt[divisor]
if cnt.get(delta//divisor) is not None and a[i] * a[j] == (delta//divisor) * (delta//divisor) + a[i] * a[j] // (delta//divisor):
ans += cnt[delta//divisor]
divisor += 1
cnt[a[j]] = cnt.get(a[j], 0) + 1
print(ans)