莫比乌斯反演

莫比乌斯反演

推式子必备知识,通常配合筛积性函数,数论分块

先介绍一下前置知识


狄利克雷卷积

定义:

函数 $h=f * g$

则 $h(n)=\sum_{d|n}f(d)g(\frac n d)=\sum_{ab=n}f(a)g(b)$

单位元:$\varepsilon=[n=1]$

$f * \varepsilon=f$

逆元:如果 $f * g = \varepsilon$,则 $g$ 为 $f$ 的逆元

性质:

  • 交换律 $f * g = g * f$

  • 结合律 $(f * g) * h = f * (g * h)$

  • 分配律 $f * g + h * g = (f+h) * g$

  • 两个积性函数的卷积也是积性函数

这可以用于判断想求的函数是否为积性函数


莫比乌斯函数

记作 $\mu$

$$ \mu(x)=\begin{cases} 1,& n = 1\\ 0,& n \text{有平方因子}\\ (-1)^k & n=p_1p_2\cdots p_k\\ \end{cases} $$

性质

积性函数

$\varphi * 1= id$

$\sum_{d|n}\mu(d)=[n=1]$

即 $\mu * 1=\varepsilon$

在狄利克雷卷积中,$\mu$ 为 $1$ 的逆元

所以,

$$[\gcd(i,j)=1]=\varepsilon(\gcd(i,j))=\sum_{d|\gcd(i,j)}\mu(d)$$

这是推式子最常用的结论之一

莫比乌斯变换

形式一:$f(n)=\sum_{d|n}g(d)$,则 $g(n)=\sum_{d|n}\mu(d)f(\frac n d)$

形式二:$f(n)=\sum_{n|d}g(d)$,则 $g(n)=\sum_{n|d}\mu(\frac n d)f(d)$


应用

线性筛法

利用它是积性函数和定义

mu[1] = 1;
for(ll i = 2; i <= mx; ++i)
{
    if(!st[i])  prime[++cnt] = i, mu[i] = -1;
    for(ll j = 1; j <= cnt && i * prime[j] <= mx; ++j)
    {
        st[i * prime[j]] = 1;
        if(i % prime[j] == 0)
        {
            mu[i * prime[j]] = 0;
            break;
        }
        mu[i * prime[j]] = -mu[i];
    }
}

常见推式子技巧

化成关于 $\gcd$ 的形式,枚举 $\gcd$ 的值

就转换成 $[\gcd(i,j)=1]$ 的式子

然后用结论,推为 $\sum_{d|\gcd(i,j)}\mu(d)$

交换求和顺序,先枚举 $d$,则 $i,j$ 均为 $d$ 的倍数

然后推成 $\lfloor\frac i {dt}\rfloor\lfloor\frac j {dt}\rfloor$

如果需要的话,接下来,令 $T=dt$,枚举 $T$

总之,先可能使 $\sum$ 变多,但最终想让 $\sum$ 变少,并化成可以预处理的形式

P2522 [HAOI2011] Problem b

如果有下界,推式子就有很多麻烦

所以用容斥,求四遍就行

$$ \sum_{i=1}^n\sum_{j=1}^m[\gcd(i,j)=k] =\sum_{i=1}^{\lfloor\frac n k\rfloor}\sum_{j=1}^{\lfloor\frac m k\rfloor} [\gcd(i,j)=1] $$$$ =\sum_{i=1}^{\lfloor\frac n k\rfloor}\sum_{j=1}^{\lfloor\frac m k\rfloor} \sum_{d|\gcd(i,j)}\mu(d)=\sum_{d}^{\min(\lfloor\frac n k\rfloor,\lfloor\frac m k\rfloor)}\mu(d)\sum_{i=1}^{\lfloor\frac n k\rfloor}[d|i]\sum_{j=1}^{\lfloor\frac m k\rfloor}[d|j] $$

$$ =\sum_{d}^{\min(\lfloor\frac n k\rfloor,\lfloor\frac m k\rfloor)}\mu(d)\lfloor\frac n {kd}\rfloor\lfloor\frac m {kd}\rfloor $$

这个式子就可以整除分块了,复杂度 $O(n\sqrt k)$

ll solve(ll n, ll m)
{
    n /= k, m /= k;
    if(!n || !m)    return 0;
    ll res = 0;
    for(ll l = 1, r = 1; l <= n && l <= m; l = r + 1)
    {
        r = min(n / (n / l), m / (m / l));
        res += (qzh[r] - qzh[l - 1]) * (n / l) * (m / l);
    }
    return res;
}
int main()
{
    mu[1] = 1;
    for(ll i = 2; i <= mx; ++i)
    {
        if(!st[i])  prime[++cnt] = i, mu[i] = -1;
        for(ll j = 1; j <= cnt && i * prime[j] <= mx; ++j)
        {
            st[i * prime[j]] = 1;
            if(i % prime[j] == 0)
            {
                mu[i * prime[j]] = 0;
                break;
            }
            mu[i * prime[j]] = -mu[i];
        }
    }
    for(ll i = 1; i <= mx; ++i) qzh[i] = qzh[i - 1] + mu[i]; 
    q = read();
    while(q--)
    {
        a = read(), b = read(), c = read(), d = read(), k = read();
        print(solve(b, d) - solve(a - 1, d) - solve(b, c - 1) + solve(a - 1, c - 1)), putchar('\n');
    }
    return 0;
}

P4449 于神之怒加强版

直接开始推

$$ \sum_{i=1}^n \sum_{j=1}^m \gcd(i,j)^k=\sum_d d^k\sum_{i=1}^{\lfloor\frac n d\rfloor}\sum_{j=1}^{\lfloor\frac m d\rfloor}[\gcd(i,j)=1] $$$$ =\sum_d d^k\sum_{i=1}^{\lfloor\frac n d\rfloor}\sum_{j=1}^{\lfloor\frac m d\rfloor}\sum_{t|\gcd(i,j)}\mu(t) $$

后面一坨跟上一题很像,直接就化简为

$$ \sum_d d^k\sum_{t}^{\min(\lfloor\frac n d\rfloor,\lfloor\frac m d\rfloor)}\mu(t)\lfloor\frac n {dt}\rfloor\lfloor\frac m {dt}\rfloor $$

但如果枚举 $d$,对 $t$ 整除分块,复杂度仍不够

令 $T=dt$,交换求和顺序,则

$$ =\sum_{T}\lfloor\frac n {T}\rfloor\lfloor\frac m {T}\rfloor\sum_{d|T}d^k \mu(\frac T d)$$

令 $f(x)=x^k$,则 $f(x)$ 为积性函数,发现 $g(T)=\sum_{d|T}f(d) \mu(\frac T d)$ 是卷积的形式

由卷积的性质得 $g(x)$ 也是积性函数,可以用欧拉筛预处理

具体的,

$$ g(n)=\begin{cases} n^k-1,& n \text{为质数}\\ n^k-(\frac n p)^k,&n=p^x,p\text{为质数}\\ \end{cases} $$

这样同时记录每个数最小的质因子的乘积,即可利用积性函数 $O(n)$ 求 $g$

对 $T$ 整除分块,复杂度 $O(T\sqrt n)$

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod = 1e9 + 7, N = 5000010, mx = 5000000, SZ = (1 << 14) + 5;
ll t, k, n, m, st[N], prime[N], ans, cnt, mn[N], f[N], g[N], low[N];
static char buf[SZ], *bgn = buf, *til = buf;
char getc()
{
    if(bgn == til)  bgn = buf, til = buf + fread(buf, 1, SZ, stdin);
    return (bgn == til) ? EOF : *bgn++;
}
ll read()
{
    char ch = getc();   ll x = 0;
    while(ch < '0' || ch > '9') ch = getc();
    while(ch >= '0' && ch <= '9')   x = (x << 1) + (x << 3) + ch - '0', ch = getc();
    return x;
}
void print(ll x)
{
    if(x / 10)  print(x / 10);
    putchar(x % 10 + '0');
}
ll add(ll a, ll b)  {return (a + b >= mod) ? (a + b - mod) : (a + b);}
ll qmi(ll a, ll b)
{
    ll res = 1;
    while(b)
    {
        if(b & 1)   res = res * a % mod;
        b >>= 1, a = a * a % mod;
    }
    return res;
}
int main()
{
    t = read(), k = read();
    f[1] = g[1] = low[1] = st[1] = 1; 
    for(ll i = 2; i <= mx; ++i)
    {
        if(!st[i])  prime[++cnt] = i, f[i] = qmi(i, k), low[i] = i, g[i] = add(f[i], mod - 1); 
        for(ll j = 1; j <= cnt && i * prime[j] <= mx; ++j)
        {
            st[i * prime[j]] = 1, f[i * prime[j]] = f[i] * f[prime[j]] % mod;           
            if(i % prime[j] == 0)   
            {
                low[i * prime[j]] = low[i] * prime[j];
                if(low[i * prime[j]] == i * prime[j])   g[i * prime[j]] = add(f[i * prime[j]], mod - f[i]); 
                else    g[i * prime[j]] = g[i / low[i]] * g[low[i] * prime[j]] % mod;
                break;
            }
            g[i * prime[j]] = g[i] * g[prime[j]] % mod, low[i * prime[j]] = prime[j];
        }
    }
//  for(ll i = 1; i <= 20; ++i) cerr << i << ": " << f[i] << " " << g[i] << " " << low[i] << "\n";
    for(ll i = 2; i <= mx; ++i) g[i] = add(g[i], g[i - 1]);
    while(t--)
    {
        n = read(), m = read(), ans = 0;
        for(ll l = 1, r = 1; l <= n && l <= m; l = r + 1)
        {
            r = min(n / (n / l), m / (m / l));
            ans = add(ans, (n / l) * (m / l) % mod * add(g[r], mod - g[l - 1]) % mod);
        }
        print(ans), putchar('\n');
    }
    return 0;
}

posted @ 2023-07-09 13:38  KellyWLJ  阅读(3)  评论(0编辑  收藏  举报  来源