容斥原理+dfs剪枝
题目要求gcd为1的四个数的组合个数,我们可以先求gcd不为1的四个数组合个数
四个数只要都有共同的一个质因数,gcd就不为1
可以求出所有质因数,然后枚举质因数的乘积,求可以被乘积整除的数有多少个
求出组合数,再用容斥原理去重
因为质因数可能很多,所以在dfs里加一些剪枝
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int N=1e4+10;
int a[N],num[N];
int p[N],cnt;
bool pri[N],vis[N];
void init()
{
memset(pri,true,sizeof(pri));
pri[1]=false;
for(int i=2;i<N;i++)
{
if(pri[i])
{
for(int j=i+i;j<N;j+=i)
pri[j]=false;
}
}
}
ll ans;
void dfs(int d,int k,int j)
{
if(k>=N) return; //剪枝
if(k>1&&num[k]<4) return; //剪枝
if(d)
{
ll s=num[k];
ll sum=s*(s-1)*(s-2)*(s-3)/2/3/4;
if(d%2==1) ans-=sum;
else ans+=sum;
}
for(int i=j;i<cnt;i++)
if(!vis[i])
{
vis[i]=true;
dfs(d+1,k*p[i],i+1);
vis[i]=false;
}
}
int main()
{
init();
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
if(n<4)
{
printf("0\n");
continue;
}
memset(num,0,sizeof(num));
cnt=0;
for(int i=0;i<n;i++)
{
int k=a[i],j;
for(j=1;j*j<k;j++)
if(k%j==0)
num[j]++,num[k/j]++;
if(j*j==k) num[j]++;
}
for(int i=2;i<N;i++)
if(pri[i]&&num[i]>=4) //至少出现过4次的质因数
p[cnt++]=i;
ans=1l*n*(n-1)*(n-2)*(n-3)/2/3/4;
memset(vis,false,sizeof(vis));
dfs(0,1,0);
printf("%lld\n",ans);
}
return 0;
}