题目描述
难度分:1200
输入T(≤104)表示T组数据。所有数据的n之和≤2×105。
每组数据输入n(2≤n≤105)和长为n的数组a(1≤a[i]≤2n),数组元素互不相同。
输出有多少对(i,j)满足i<j且a[i]×a[j]=i+j。
输入样例
3
2
3 1
3
6 1 5
5
3 1 5 9 2
输出样例
1
1
3
算法
试除法
由于数组a中的元素满足a[i]≤2n并不是很大,所以对于某个a[i]=s,可以在O(√n)的时间复杂度下分解出两个不同的因子d1和d2,只要d1和d2都在数组a就凑出了一个数对。
先预处理出一个id数组,id[a[i]]表示a[i]在数组a中的索引i。然后枚举s∈[1,2n],对s分解,计算s对答案的贡献即可。
复杂度分析
时间复杂度
遍历s的时间复杂度为O(n),对s分解的时间复杂度为O(√n)。因此,整个算法的时间复杂度为O(n1.5)。
空间复杂度
除了输入的数组a,空间消耗主要在于id数组,它是O(n)规模的,这也是整个算法的额外空间复杂度。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 200010;
int t, n, a[N], id[N<<1];
int main() {
scanf("%d", &t);
while(t--) {
scanf("%d", &n);
for(int i = 1; i <= n*2; i++) {
id[i] = 0;
}
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
id[a[i]] = i;
}
int ans = 0;
for(int s = 1; s <= 2*n; s++) {
for(int d1 = 1; d1 <= s/d1; d1++) {
int d2 = s / d1;
if(d1 < d2 && (id[d1] > 0 && id[d2] > 0) && d1*d2 == s && (id[d1] + id[d2] == s)) {
ans++;
}
}
}
printf("%d\n", ans);
}
return 0;
}