统计一下每个约数在数列中是多少数的约数,然后就是容斥原理搞一下。
对任意一个数,求其三个数互质或三个数全不互质的数量,就是总数减去三个数两个互质剩余至少一对不互质的个数。对于一个数a,数列中的数要么与其互质,要么不互质,假设互质的数的个数为n1,那么不互质的数的个数就是n-n1-1,然后取三个数就是取一个与a互质的和一个与a不互质的数,取法共有n1*(n-n1-1),这样取的话会重复一遍,可以假设以a为轴取的三个数为a,b,c,其中a和b互质,a和c不互质,如果b和c也互质,那么以c为轴取的c,b,a重复了一遍,如果b,c不互质,那么b,a,c重复了一遍,所以最后算出的结果总数要除2,便是三个数两个互质且第至少有一对不互质的取法个数,然后再用总数减一下就得到了结果。
附代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
ll v[100010];
int have[100010];
ll ss[100010];
ll maxn;
ll n;
void build()
{
memset(have,0,sizeof(have));
for (int i=1;i<=n;i++)
have[v[i]]=1;
for (int i=2;i<=maxn;i++)
for (int t=i;t<=maxn;t+=i)
if (have[t])
ss[i]++;
return ;
}
ll solve(int k)
{
vector <int> p;
for (int i=2;i*i<=k;i++)
{
if (k%i==0)
p.push_back(i);
while (k%i==0)
k/=i;
}
if (k>1)
p.push_back(k);
int mm=(1<<p.size())-1;
ll ans=0;
for (int i=1;i<=mm;i++)
{
ll pp=1;
ll cc=0;
for (int t=0;t<p.size();t++)
{
int x=(1<<t);
int temp=i;
if (temp&x)
{
pp*=p[t];
cc++;
}
temp>>=1;
}
if (cc&1)
ans+=ss[pp]-1;
else
ans-=ss[pp]-1;
}
return (n-ans-1)*ans;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
maxn=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
if (v[i]>maxn)
maxn=v[i];
}
memset(ss,0,sizeof(ss));
build();
ll ans=0;
for (int i=1;i<=n;i++)
ans+=solve(v[i]);
ll a1=(n*(n-1)*(n-2))/6;
ans=a1-ans/2;
printf("%I64d\n",ans);
}
}