给出一些数,挑选其中3个,求两两互质和两两不互质的方案数。
需要对唯一分解原理有一定的理解,两个数不互质无非就是质因数分解后有相同的部分,比如a质因数分解为p1*p2*p3*p4...(指数省略),与a不互质的数有p1的倍数,p2的倍数...,根据容斥原理还需减去p1*p2的倍数,总结就是奇数个加,偶数个减。
本题求得两两互质和两两不互质的反面是,两对互质一对不互质和两队不互质一对互质,求出与每个数互质与不互质的个数,相乘,最后除2即可。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<bitset>
#define fi first
#define se second
#define pii pair<int,int>
#define ll long long
#define inf 1<<30
#define eps 1e-8
using namespace std;
const int maxn=100005;
int n;
int d[maxn];
int num[maxn];
bool vis[maxn];
int prime[maxn];
int sum[maxn];
int cnt;
int p[maxn];
int now;
void getPrime()
{
int N=100000;
int m=sqrt(N+0.5);
memset(vis,0,sizeof(vis));
for(int i=2;i<=m;i++) {
if(vis[i]==0) {
for(int j=i*i;j<=N;j+=i)
vis[j]=1;
}
}
cnt=0;
for(int i=2;i<=N;i++) {
if(vis[i]==0)
prime[cnt++]=i;
}
}
ll ans;
void dfs(int k,int tot)
{
if(k==now) {
if(tot!=1)
sum[tot]++;
return;
}
dfs(k+1,tot);
dfs(k+1,tot*p[k]);
}
void gao(int a)
{
now=0;
for(int i=0;i<cnt;i++) {
if(prime[i]*prime[i]>a)
break;
if(a%prime[i]==0)
p[now++]=prime[i];
while(a%prime[i]==0)
a/=prime[i];
}
if(a>1)
p[now++]=a;
dfs(0,1);
}
ll uu;
void Dfs(int k,int tot,int o)
{
if(k==now) {
if(tot!=1) {
if(o&1)
uu+=sum[tot];
else
uu-=sum[tot];
}
return;
}
Dfs(k+1,tot,o);
Dfs(k+1,tot*p[k],o+1);
}
ll L(int a)
{
now=0;
for(int i=0;i<cnt;i++) {
if(prime[i]*prime[i]>a)
break;
if(a%prime[i]==0)
p[now++]=prime[i];
while(a%prime[i]==0)
a/=prime[i];
}
if(a>1)
p[now++]=a;
uu=0;
Dfs(0,1,0);
return uu;
}
int main()
{
getPrime();
int t;
int a;
scanf("%d",&t);
while(t--) {
memset(sum,0,sizeof(sum));
memset(num,0,sizeof(num));
scanf("%d",&n);
for(int i=0;i<n;i++) {
scanf("%d",&a);
num[a]++;
gao(a);
}
ans=0;
for(int i=1;i<=100000;i++) {
if(num[i]==0)
continue;
ll u=L(i);
if(u==0)
continue;
ans+=(u-1)*(n-u)*num[i];
}
ans/=2;
ans=(ll)n*(n-1)*(n-2)/6-ans;
printf("%I64d\n",ans);
}
return 0;
}