题意:是给你n个数,然后问你有多少组数(每组3个数)满足两两互质或者两两不互质。
思路:问题可以转换成一张完全图中有n个点,每两个点间有一条线,互质是黑色,不互质是白色。问图种有多少个单色三角形。
正面直接求不好求,我们就反面求,求有多少个不纯色三角形。最后从
C3n
中减去。
那如何求不纯色三角形呢?我们发现只要一个三角形满足一条边是黑(互质)一条边是白(不互质)就行了。所以我们问题可以转化成,对于每个数我们可以求出有多少个数和他不互质,然后互质的就是n-1-k。乘一下就好了。最后统计的是后除个2.
具体实现,我们可以用一个vector来预处理出
105
的每个数的约数。然后对于每一组输入,对每一个对入的数,暴力dfs每个约数,在vis数组中加入。然后再跑一边dfs,对于每一个数,dfs每一个约数,用容斥求一下有多少个不互质的。
容斥的做法很简单,根据这个约数是由多少个质因数组成的来确是加这个数还是减这个数。
#include<bits/stdc++.h>
#define maxn 111111
using namespace std;
int np=0;
int prime[maxn];
int vis[maxn];
int a[maxn];
int b[20];
int sum;
int sz;
vector<int> fac[maxn];
void init(void) {
memset(vis,0,sizeof vis);
for(int i=2;i<maxn;i++)
if(!fac[i].size()) {
prime[++np]=i;
fac[i].push_back(i);
for(int j=i+i;j<maxn;j+=i) {
fac[j].push_back(i);
}
}
}
void dfs1(int now,int s) {
if(now==sz+1) {
vis[s]++;
return;
}
dfs1(now+1,s);
dfs1(now+1,s*b[now]);
}
void dfs2(int now,int tt,long long s,int all) {
if(now==sz+1) {
if(tt==all) {
sum+=vis[s];
}
return;
}
dfs2(now+1,tt,s,all);
dfs2(now+1,tt+1,s*b[now],all);
}
int main()
{
init();
int t,n;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
sz=fac[a[i]].size();
for(int j=1;j<=sz;j++) {
b[j]=fac[a[i]][j-1];
}
dfs1(1,1);
}
long long ans=0;
for(int i=1;i<=n;i++) {
long long fa=1;
long long tot=0;
sz=fac[a[i]].size();
for(int j=1;j<=sz;j++) {
b[j]=fac[a[i]][j-1];
}
if(a[i]!=1)
for(int j=1;j<=sz;j++) {
sum=0;
dfs2(1,0,1,j);
if(j%2==1) {
tot+=sum;
}
else {
tot-=sum;
}
}
if(a[i]==1) {
ans+=0;
}
else
if(tot!=0) {
ans+=(tot-1)*(n-tot);
}
}
printf("%lld\n",(long long )n*(n-1)*(n-2)/6-ans/2);
}
return 0;
}