首页 > 代码库 > [HDU 5072] Coprime 莫比乌斯反演

[HDU 5072] Coprime 莫比乌斯反演

题意

  ? 给定一个长度为 $n$ 的序列 $A = \left\{ a_1, a_2, ..., a_n \right\}$ .

  ? 问有多少个三元组 $(i, j, k)(i \ne j, i \ne k, j \ne k)$ , 满足 $\left\{ \begin{aligned} & a_i \perp a_j \\ & a_i \perp a_k \\ & a_j \perp a_k \end{aligned} \right.$ 或 $\left\{ \begin{aligned} & a_i \not \perp a_j \\ & a_i \not \perp a_k \\ & a_j \not \perp a_k \end{aligned} \right.$ .

  ? $1 \le n, a_i \le {10}^5$ .

 

预备知识

  ? $k | (x, y) \Leftrightarrow \left\{ \begin{aligned} & k | x \\ & k | y \end{aligned} \right.$

  ? 证明 (1) 必要性.

    ? $k | (x, y) , (x, y) | x, (x, y) | y \Rightarrow k | x, k | y$ .

  ? (2) 充分性.

    ? $\exists p, q \in \mathbb{Z}, ~s.t.~ px + qy = (x, y)$ .

    ? $k | x, k | y \Rightarrow k | px + qy \Rightarrow k | (x, y)?$ .

 

  ? $g_n = \sum_{d | n} f_n \Leftrightarrow f_n = \sum_{d | n} \mu(d) g(\frac{n}{d})$ .

  ? 由 $f_1, f_2, ..., f_n$ 求 $g_1, g_2, ..., g_n$ : 从小到大枚举 $d$ , 将 $f_d$ 加到 $g_d, g_{2d}, g_{3d}, ...$ .

  ? 由 $g_1, g_2, ..., g_n$ 求 $f_1, f_2, ..., f_n$ :

    ? 方法一 从小到大枚举 $d$ , 此时我们已经算出 $f_1, f_2, ..., f_d$ , 将 $g_{2d}, g_{3d}, ..., g_{kd}$ 减去 $f_d$ .

    ? 方法二 反演公式.

?

  ? $g_n = \sum_{n | d} f_d \Leftrightarrow f_n = \sum_{n | d} \mu(\frac{d}{n}) g(d)$

  ? 由 $f_1, f_2, ..., f_n$ 求 $g_1, g_2, ..., g_n$ : 枚举 $d$, 将 $f_d, f_{2d}, ...$ 加到 $g_d$ .

  ? 由 $g_1, g_2, ..., g_n$ 求 $f_1, f_2, ..., f_n$ :

    ? 方法一 从大到小枚举 $d$ , 将 $g_d$ 减去 $f_{2d}, f_{3d}, ...$ 得到 $f_d$ .

    ? 方法二 反演公式.

 

分析

  ? $n$ 个点的完全图, 边有两种颜色, 求同色三角形个数.

 

  ? 减法原理, $\binom{n}{3} - 不同色三角形个数$ .

  ? 枚举每个点, 算出该点除外的互质个数 $a$ , 该点除外的不互质个数 $b$ , 那么贡献 $a \times b$ .

  ? 发现每个不同色三角形, 我们恰好算了两次, 所以 $\frac{1}{2} (\sum a\times b)$ 即可.

 

  ? 当 $a_i = 1$ 时, 不产生贡献.

  ? 当 $a_i \ne 1$ 时, $该点除外的互质个数 = 互质个数 = a$ , $该点除外的不互质个数 = 不互质个数 - 1 = n - 1 - a$ .

 

  ? 给定 $a_1, a_2, ..., a_n$ , 求与 $x$ 互质的数的个数.

  ? 设 $c_d = \sum_{i} [a_i = d]$ , $f_x$ 为与 $x$ 互质的数的个数.

  $$\begin{aligned} f_x & = \sum{d} [d \perp x] c_d \\ & = \sum_{k | d, d | x}\mu(k)c_d \\ & = \sum_{k | x} \mu(k) \sum_{k | d} c_d \end{aligned}$$
  ? 枚举 $k$ , $O(\frac{n}{k})$ 求 $\sum_{k | d}c_d$ , 再 $O(\frac{n}{k})$ 对 $f_k, f_{2k}, ..., f_{pk}, ...$ 进行贡献.

  ? 总时间复杂度 $O(n \log n)$ .

?

实现

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>

#define F(i, a, b) for (register int i = (a); i <= (b); i++)

#define LL long long

const int N = 100005;
const int A = 100000;

bool v[N]; int p[N], tot, mu[N];
int n, a[N];
LL c[N], f[N];
LL res;

inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}

int main(void) {
    #ifndef ONLINE_JUDGE
        freopen("hdu5072.in", "r", stdin);
        freopen("hdu5072.out", "w", stdout);
    #endif
    
    v[1] = true, mu[1] = 1;
    F(i, 2, A) {
        if (!v[i]) p[++tot] = i, mu[i] = -1;
        for (int j = 1; i * p[j] <= A && j <= tot; j++) {
            v[i * p[j]] = true;
            if (i % p[j] != 0) mu[i * p[j]] = -mu[i]; else break;
        }
    }
    
    for (int nT = rd(), t = 1; t <= nT; t++) {
        memset(a, 0, sizeof a);
        n = rd(); F(i, 1, n) a[i] = rd();
        
        memset(c, 0, sizeof c), memset(f, 0, sizeof f);
        F(i, 1, n) c[a[i]]++;
        F(k, 1, A) if (mu[k] != 0) {
            LL t = 0;
            for (int d = k; d <= A; d += k)
                t += c[d];
            t *= mu[k];
            for (int x = k; x <= A; x += k)
                f[x] += t;
        }
        
        res = 0;
        F(i, 1, n)
            if (a[i] != 1)
                res += f[a[i]] * (n - 1 - f[a[i]]);
        printf("%I64d\n", 1LL * n * (n-1) * (n-2) / 6 - res / 2);
    }
    
    return 0;
}

 

[HDU 5072] Coprime 莫比乌斯反演