luogu2714 Statistical Mobius Inversion Combinations of Quaternary Groups

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;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325006342&siteId=291194637