Problem Description
Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to steal the spacecraft of Petru. There is only one problem – Petru has locked the spacecraft with a sophisticated cryptosystem based on the ID numbers of the stars from the Milky Way Galaxy. For breaking the system Stancu has to check each subset of four stars such that the only common divisor of their numbers is 1. Nasty, isn’t it? Fortunately, Stancu has succeeded to limit the number of the interesting stars to N but, any way, the possible subsets of four stars can be too many. Help him to find their number and to decide if there is a chance to break the system.
Input
In the input file several test cases are given. For each test case on the first line the number N of interesting stars is given (1 ≤ N ≤ 10000). The second line of the test case contains the list of ID numbers of the interesting stars, separated by spaces. Each ID is a positive integer which is no greater than 10000. The input data terminate with the end of file.
Output
For each test case the program should print one line with the number of subsets with the asked property.
Sample Input
4
2 3 4 5
4
2 4 6 8
7
2 3 4 5 7 6 8Sample Output
1
0
34
题意:多组数据,每组数据给出 n 个数构成一个集合,问有多少个不同的含有四个元素的子集 (a,b,c,d) 他们的最大公约数为 1
思路:
题目本质是要求有多少个 (a,b,c,d) 的 GCD(a,b,c,d)=1
设 F(k) 为有多少对(a,b,c,d)满足 GCD(a,b,c,d)=k 的个数的倍数,f(k) 为有多少对(x,y)满足 GCD(a,b,c,d)=k 的个数
因此,有:,可以看出,其符合莫比乌斯反演的形式
那么有:
根据 F(k) 的定义可知,只要在原来的集合中找出能被 n 整除的数的个数 m,然后 C(m,4) 即为 F(n)
由于要求 GCD(a,b,c,d)=1,因此对于 f(k),k 取 1 即为答案
因此,可得:,其中 N 是数据范围
Source Program
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define EPS 1e-9
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
const int MOD = 1E9+7;
const int N = 10000+5;
const int dx[] = {0,0,-1,1,-1,-1,1,1};
const int dy[] = {-1,1,0,0,-1,1,-1,1};
using namespace std;
LL n;
LL mu[N],prime[N];
bool bprime[N];
LL a[N],num[N];
void getMu(LL n){//线性筛求莫比乌斯函数
mu[1]=1;//根据定义,μ(1)=1
LL cnt=0;
memset(bprime,false,sizeof(bprime));
for(LL i=2;i<=n;i++){//求2~n的莫比乌斯函数
if(!bprime[i]){
prime[cnt++]=i;//存储质数
mu[i]=-1;//i为质数时,μ(1)=-1
}
for(LL j=0;j<cnt;j++){//枚举i之前的素数个数
LL k=i*prime[j];//素数的乘积
if(k>n)//剪枝
break;
bprime[k]=true;//不是质数
if(i%prime[j])//i不是primes[j]的整数倍时,i*prime[j]就不会包含相同质因子
mu[k]=-mu[i];//mu[k]=mu[i]*mu[prime[j]],因为prime[j]是质数,mu值为-1
else{
mu[k]=0;
break;//留到后面再筛
}
}
}
}
LL Cn4(LL m){
if(m==0)
return 0;
return m*(m-1)*(m-2)*(m-3)/24;
}
void getM(){
memset(num,0,sizeof(num));
for(LL i=0;i<n;i++){
LL x=a[i];
LL m=sqrt(x);
for(LL j=1;j<=m;j++){
if(x%j==0){
num[j]++;
num[x/j]++;
}
}
if(m*m==x)
num[m]--;
}
}
int main(){
getMu(N);
while(scanf("%lld",&n)!=EOF&&n){
for(LL i=0;i<n;i++)
scanf("%lld",&a[i]);
getM();
LL res=0;
for(LL i=1;i<N;i++)
res+=mu[i]*Cn4(num[i]);
printf("%lld\n",res);
}
return 0;
}