四元组统计
题目链接:luogu P2714
题目大意
给你 n 个数,问你有多少个四元组满足它们四个的 gcd 为 1。
思路
考虑到我们是要
gcd
\gcd
gcd 为
1
1
1,那就是要每个质数每个数的出现个数的最小值都是
0
0
0。
考虑一个类似容斥的过程,就是我们可以求
f
i
f_i
fi 表示有多少个数至少都是
i
i
i 的倍数。(这个直接高维前缀和)
那你求出个数
x
x
x 之后直接变成
(
x
4
)
\Large\binom{x}{4}
(4x),然后你这个部分还要容斥,那你可以莫反(所以其实你可以不用高维前缀和而是把莫反
μ
\mu
μ 不是
0
0
0 的位置只求这些好像也可以过还很快)。
也可以直接高维差分。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 1e4 + 100;
int n, a[N], m, prime[N];
bool np[N];
ll f[N];
void Init() {
for (int i = 2; i < N; i++) {
if (!np[i]) prime[++prime[0]] = i;
for (int j = 1; j <= prime[0] && i * prime[j] < N; j++) {
np[i * prime[j]] = 1; if (i % prime[j] == 0) break;
}
}
}
int main() {
Init();
while (scanf("%d", &n) != EOF) {
m = 0; for (int i = 1; i <= n; i++) scanf("%d", &a[i]), m = max(m, a[i]);
for (int i = 1; i <= m; i++) f[i] = 0; for (int i = 1; i <= n; i++) f[a[i]]++;
for (int i = 1; i <= prime[0] && prime[i] <= m; i++)//高维前缀和
for (int j = m / prime[i]; j >= 1; j--)
f[j] += f[j * prime[i]];
for (int i = 1; i <= m; i++) f[i] = f[i] * (f[i] - 1) * (f[i] - 2) * (f[i] - 3) / 4 / 3 / 2;//乘上组合数
for (int i = 1; i <= prime[0] && prime[i] <= m; i++)//高维差分
for (int j = 1; j * prime[i] <= m; j++)
f[j] -= f[j * prime[i]];
printf("%lld\n", f[1]);
}
return 0;
}