题意:给n个数,求它们能够组成的四元组(a, b, c, d)的个数,其中gcd(a, b, c, d) = 1。
思路:容斥原理求出不满足要求的四元组个数,
比如若这n个数只有2,3,5三种质因数,设P[i]为n个数中有约数为i的数的个数,则不满足的个数为:
C(P[2], 4) + C(P[3], 4) + C(P[5], 4) - C(P[2 * 3], 4) - C(P[2 * 5], 4) - C(P[3 * 5], 4) + C(P[2 * 3 * 5], 4);
需要注意的是只有几个不同质数的乘积才能计入答案,如上式中不应考虑4,9,12等。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define For(i,j,k) for(LL i = j;i <= k;i ++)
const int N = 10010;
using namespace std;
typedef long long LL;
LL C[N], Num[N], cnt[N];
void init(){
For(i,2,N - 1){
C[i] = i * (i - 1) * (i - 2) * (i - 3) / 24;
if(!Num[i])Num[i] = 1;
for(LL j = i * 2;j < N;j += i)
Num[j] = max(Num[j], Num[i] + 1);
}
}
void solve(LL x){
LL p[15], s = 0;
for(LL i = 2;i * i <= x;i ++)
if(x % i == 0){
p[s++] = i;
while(x % i == 0)x /= i;
}
if(x > 1)p[s++] = x;
for(LL i = 1;i < (1 << s);i ++){
LL sum = 1;
For(j,0,s-1)
if(i & (1 << j))sum *= p[j];
cnt[sum]++;
}
}
int main(){
init();
LL n, x;
while(scanf("%lld", &n) == 1){
memset(cnt, 0, sizeof(cnt));
For(i,1,n) scanf("%lld", &x), solve(x);
LL Ans = C[n];
For(i,2,N-1){
if(Num[i] & 1)
Ans -= C[cnt[i]];
else Ans += C[cnt[i]];
}
printf("%lld\n", Ans);
}
return 0;
}