题目描述
有(n)个正整数(a_i),你要统计有多少个四元组满足(mathrm{gcd}(a_i,a_j,a_k,a_l) = 1)。
题解
这道题思路很显然,就是枚举(gcd)的思路。
我们用(f[x])表示(x)以及(x)的倍数的出现次数,输入时先把该数的出现次数统计了,然后可以(O(n*ln n))加上他的倍数的出现次数。
然后考虑答案的计算。
如果(gcd)是(x)或者(x)的倍数的话,方案数显然是(frac{f[x] * (f[x] - 1) * (f[x] - 2) * (f[x] - 3)}{24})(由于同一种选择随意排列有(4!=24)种情况,所以除以(24))。
那么转化成(gcd)是(x)的方案数,我们就需要简单容斥一下,减去(gcd)是(2*x,3*x...k*x)的方案数,所以我们倒着循环,就可以再次在(O(n*ln n))的时间统计了。
#include <iostream>
#include <cstdio>
#define ll long long
using namespace std;
const int N = 1e4 + 5;
int mx, n;
ll f[N];
inline int read()
{
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
return x * f;
}
void work()
{
while(scanf("%d", &n) != EOF)
{
for(int i = 1; i <= mx; i ++) f[i] = 0; mx = 0;
for(int i = 1, x; i <= n; i ++) {x = read(); f[x] ++; mx = max(mx, x);}
for(int i = 1; i <= mx; i ++) for(int j = 2 * i; j <= mx; j += i) f[i] += f[j];
for(int i = mx; i >= 1; i --)
{
f[i] = f[i] * (f[i] - 1) * (f[i] - 2) * (f[i] - 3) / 24;
for(int j = 2 * i; j <= mx; j += i) f[i] -= f[j];
}
printf("%lld
", f[1]);
}
}
int main() {return work(), 0;}