题目大意:给出一个n个数的数组,问有多少个三元组(a[i],a[j],a[k])满足lcm(a[i],a[j])<=gcd(a[j],a[k]),只要两个三元组中任意两个数不同,就算做两个不同的三元组
3<=n<=2e5;1<=a[i]<=2e5
思路:因为两个数的最大公因数一定小于等于两个数中最小的那个数,两个数的最小公倍数一定大于等于两个数中最大的那个数,所以要让lcm(a,b)<=gcd(b,c),唯一成立的条件就是lcm=gcd=b。
因为lcm(a,b)=b,所以a是b 的因数,因为gcd(b,c)=b,所以c是b的倍数,那么我们如果知道b有多少个因数在数组中,记为cnt1[b],有多少个倍数在数组中,记为cnt2[b],那么以b作为三元组中间的那个数时就有cnt1[b]*cnt2[b]个合法三元组。
那么怎么求因数和倍数的数量呢,我们首先记录数组中每个数的出现次数cnt[a[i]],然后遍历数组中所有不重复的数字,对其进行因式分解,如果x是a[i]分解出来的一个因数,且x在数组中,那么cnt1[a[i]]就应该+=cnt[x],cnt2[x]+=cnt[a[i]]。
最后遍历数组,累加cnt1[a[i]]*cnt2[a[i]]的值即可。
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
const ll MOD = 1e9 + 7;
ll n;
int a[N];
ll cnt1[N], cnt2[N];
ll cnt[N];
bool vis[N];
void init()
{
for (int i = 1; i <= 200000; i++)
{
cnt[i] = cnt1[i] = cnt2[i] = 0;
vis[i] = 0;
}
}
void solve()
{
cin >> n;
init();
for (int i = 1; i <= n; i++)
{
cin >>a[i];
cnt[a[i]]++;//记录数组中每个数的出现次数
}
for (int i = 1; i <= n; i++)
{
if (vis[a[i]])
continue;//只分解第一次出现的数
vis[a[i]] = 1;
ll temp = a[i];
for (int j = 1; j * j <= temp; j++)
{
if (temp % j == 0)
{
if (cnt[j])
{//a[i]%j=0求j在数组中,就维护a[i]的因数数量和j的倍数的数量
cnt1[j]+=cnt[a[i]];
cnt2[a[i]]+=cnt[j];
}
ll temp2 = temp / j;
if (temp2 != j)
{
if (cnt[temp2])
{
cnt1[temp2] += cnt[a[i]];
cnt2[a[i]] += cnt[temp2];
}
}
}
}
}
ll ans = 0;
for (int i = 1; i <= n; i++)
{
ans += cnt1[a[i]] * cnt2[a[i]];
}
cout << ans;
cout << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int t;
//cin >> t;
t=1;
while (t--)
{
solve();
}
return 0;
}