莫比乌斯反演简单证明+莫比乌斯反演入门题Sky Code

首先莫比乌斯反演

定理:g(n)f(n)都是算术函数,并且满足如下条件:f(n)=\sum _{d|n}g(d)

则有如下结论:g(n)=\sum_{d|n}\mu (d)*f(\frac{n}{d})

首先我们说一下莫比乌斯函数

1.首先当n=1时,并且\sum _{d|n}\mu(d)=[n=1]表示当n=1时才为1

2.当n=\prod_{i=1}^{k}p_{i}时,p_{i}为互异素数时,\mu (x)=(-1)^{k}

3.只要当n含有任何素因子的幂次大于等于2,则函数值为0;

4.\sum_{d|n}\frac{\mu(d)}{d}=\frac{\varphi(n) }{n}

这里从定义上面去证明:

根据定义以及基本运算法则:\sum_{d|n}\mu(d)*f(\frac{n}{d})=\sum_{d|n}(\mu(d)*\sum_{e|\frac{n}{d}}g(e))=\sum_{d|n}\sum_{e|\frac{n}{d}}(\mu(d)*g(e))

稍微思考一下可以得到(d,e)就是(d*e)|n的一个二元组合,因此可以交换两个sum的位置

\sum_{e|n}\sum_{d|\frac{n}{e}}(\mu(d)*g(e))=\sum_{e|n}g(e)*\sum_{d|\frac{n}{e}}\mu(d)

再结合性质可以得到当e=n时n/e=1因此,就等于g(n)

另外我们做题用得比较多的是另一种形式

f(n)=\sum_{n|d}g(d)\Rightarrow g(n)=\sum_{n|d}\mu(\frac{d}{n})*f(d)

这种也简单证明一下首先另k=d/n;

\sum_{k=1}^{\infty }(\mu(k)*f(n*k))=\sum_{k=1}^{\infty }(\mu(k)*\sum_{nk|t}f(t))=\sum_{n|t}(f(t)*\sum_{k|\frac{t}{n}}\mu(k))

再结合性质可以得到当t=n时t/n=1因此,就等于g(n)

https://vjudge.net/problem/UVALive-4184

http://poj.org/problem?id=3904

题意:给出n个数,问从中选出四个数使得gcd(a,b,c,d)=1,一共有多少组,a,b,c,d;

做法:这种题一看推公式肯定是莫比乌斯反演,趁热打铁加深一下记忆。

首先令f(n)为表示f(n)=\sum[gcd(a,b,c,d)=n*t] 其中表示整数倍

然后令g(n)为表示g(n)=\sum [gcd(a,b,c,d)=n]

f(n)=\sum _{n|d}g(d)

g(n)=\sum_{n|d}\mu(\frac{d}{n})*f(d)

g(1)=\sum\mu(d)*f(d)

而f(d)很好求,简单的组合数。

#include "bits/stdc++.h"

using namespace std;
const double eps = 1e-8;
#define reg register
#define lowbit(x) x&-x
#define pll pair<ll,ll>
#define pii pair<int,int>
#define fi first
#define se second
#define makp make_pair

int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return (x > 0) ? 1 : -1;
}

typedef long long ll;
typedef unsigned long long ull;
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const int N = 10000 + 10;
const int M = 1000 + 10;
const int inf = 0x3f3f3f3f;
const ll mod = 998244353;
int vis[N], pri[N], mu[N], cnt, n, tot[N], a[N];

void init() {
    vis[1] = mu[1] = 1;
    cnt = 0;
    for (int i = 2; i < N; i++) {
        if (!vis[i]) {
            pri[++cnt] = i;
            mu[i] = -1;
        }
        for (int j = 1; j <= cnt && i * pri[j] < N; j++) {
            vis[i * pri[j]] = 1;
            if (i % pri[j] == 0) break;
            mu[i * pri[j]] = -mu[i];
        }
    }
}

void get_tot() {
    memset(tot, 0, sizeof(tot));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j * j <= a[i]; j++) {
            if (a[i] % j == 0) tot[j]++, tot[a[i] / j]++;
            if (j * j == a[i]) tot[j]--;
        }
    }
}

ll C(int m) {
    return 1LL * m * (m - 1) * (m - 2) * (m - 3) / 24;
}

int main() {
    init();
    while (~scanf("%d", &n)) {
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
        }
        get_tot();
        ll ans = 0;
        for (int i = 1; i < N; i++) {
            ans += 1LL * mu[i] * C(tot[i]);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
发布了130 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/KXL5180/article/details/97270091
今日推荐