Topic
Given a sequence, find the number of quadruplets in which the greatest common divisor is 1.
ideas
We have to use the idea of inversion, right and wrong. For each number \(x\) greater than 1, find the number of quadruplets with the greatest common divisor of \(x\) \(g(x)\) , and then use the combination of all quadruplets in the permutation Subtract \(\sum g(x)\) from the number . There is no idea
to directly find \(g(x)\) , but it will be easier to find the number of quadruplets with \(x\) in the common divisor \(f(x)\) . The number of elements in the array of x in the enumeration divisor \(n\) , then there is
\[f(x)=C_n^4\]
Then how to change \(f(x)\) into \(g( What about x)\) ? This uses a Mobius inversion.
Mobius inversion
Mobius function
\[ \mu(x)= \begin{cases} 1 &\text{if $x$=1}\\ 0 &\text{if every prime number obtained by factoring $x$ has a degree greater than 1}\\ (-1)^k &\text{$k$ is the number of prime factors of $x$} \end{cases} \]
Mobius inversion formula
若
\[f(x)=\sum_{k=1}^{\lfloor \frac{N}{x}\rfloor}g(kx)\tag{1}\]
则
\[g(x)=\sum_{k=1}^{\lfloor \frac{N}{x}\rfloor}f(kx)\mu(k)\]
We found that if the maximum number in the sequence is taken as \(N\) , \(f(x),g(x)\) just satisfies the relation (1). So we can follow the formula to find \(g(x)\) .
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
const int MAX_N = 10010, MAX_R = 5, MAX_PRIME_CNT = MAX_N;
ll C[MAX_N][MAX_R];
int Num[MAX_N], Mu[MAX_N];
ll F[MAX_N];
void GetMu(int *mu, int n)
{
static bool NotPrime[MAX_N];
static int prime[MAX_PRIME_CNT];
memset(NotPrime, false, sizeof(NotPrime));
int primeCnt = 0;
mu[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!NotPrime[i])
{
prime[primeCnt++] = i;
mu[i] = -1;
}
for (int j = 0; j < primeCnt; j++)
{
if (i*prime[j] > n)
break;
NotPrime[i*prime[j]] = true;
if (i%prime[j] == 0)
{
mu[i*prime[j]] = 0;
break;
}
else
mu[i*prime[j]] = -mu[i];
}
}
}
void GetC(int r, int n)
{
memset(C, 0, sizeof(C));
for (int i = 1; i <= n; i++)
{
C[i][0] = 1;
for (int j = 1; j <= min(i, r); j++)
{
if (i == j)
C[i][j] = 1;
else
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
}
}
ll Proceed(int maxN, int n)
{
memset(F, 0, sizeof(F));
for (int i = 2; i <= maxN; i++)
{
int cnt = 0;
for (int j = 1; j <= maxN / i; j++)
cnt += Num[i * j];
F[i] = C[cnt][4];
}
ll ans = 0;
for (int i = 2; i <= maxN; i++)
for (int j = 1; j <= maxN / i; j++)
ans += F[i * j] * Mu[j];
return C[n][4] - ans;
}
int main()
{
GetMu(Mu, 10000);
GetC(4, 10000);
int n, maxN = 0, x;
while (~scanf("%d", &n))
{
memset(Num, 0, sizeof(Num));
for (int i = 1; i <= n; i++)
{
scanf("%d", &x);
Num[x]++;
maxN = max(maxN, x);
}
printf("%lld\n", Proceed(maxN, n));
}
return 0;
}