题意:
给出n个数,输出能由4个数组成的最小公约数是1的总个数。
思路:
很容易想到可以用总的组合数减去最小公约数不为一的数的个数。
但是该怎么求呢?
可以先求出每一个数能够被整除的因子,保存个数于count之中,那么剩下的就是
找出四个数因子不为1的组合个数。
比如:2的因子个数总和为a个,3有b个,6有c个。那么所求就是
ans = C(n,4) - { C(a,4) + C(b,4) - C(c,4) };
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 10005;
int n,m;
int count[MAXN];
__int64 A[MAXN];
int num[MAXN];
int prim[MAXN];
void init()
{
memset(num,0,sizeof(num));
memset(A,0,sizeof(A));
for(__int64 i = 4;i < MAXN; i++) {
A[i] = i*(i-1)*(i-2)*(i-3)/24;
}
}
void solve(int n)
{
int pos = 0;
for(int i = 2;i*i <= n; i++) {
if(n%i == 0) {
prim[pos++] = i;
}
while(n%i == 0)
n /= i;
}
if(n != 1)
prim[pos++] = n;
for(int i = 1;i < (1 << pos); i++) {
int sum = 0;
int k = 1;
for(int j = 0;j < pos; j++) {
if(i & (1<<j)) {
k *= prim[j];
sum ++;
}
}
count[k]++;
num[k] = sum;
}
}
int main()
{
//freopen("in.txt","r",stdin);
init();
while(scanf("%d",&n) != EOF) {
memset(count,0,sizeof(count));
for(int i = 0;i < n; i++) {
scanf("%d",&m);
solve(m);
}
__int64 ans = 0;
for(int i = 0;i < MAXN; i++) {
if(count[i]) {
if(num[i]%2) {
ans += A[count[i]];
}
else
ans -= A[count[i]];
}
}
printf("%I64d\n",A[n]-ans);
}
return 0;
}