简易数论函数变换学习

积性函数

当$(n,m) = 1$时有$f(nm) = f(n)f(m)$,则称$f(x)$ 为积性函数。

线性筛法

对于每一个数字$n$,用其最小的质因数筛去,考虑最小质因数 $p$ 与数字 $n$ 的三种情况

1. $n = p$ 。

2. $p|n, p<n$

3. $else$

三种情况分别考虑即可。

以欧拉函数为例:

1. $\phi (i) = i-1$

2. $\phi (tp) = \phi (t) \times p$

3. $\phi (tp) = (p-1) \times \phi(t) $ 这样可以 $O(n)$ 筛出相应函数

例:求出 1~n! 中与 m! 互质的数字个数。

x 与 m! 互质 <-> x 与 1 ~ m 互质 <-> x 不含有 ≤ m的质数。

这样考虑 $x = m!t + k$

$p | x$ <=> $p | k$,这样有 $ans = m! \prod {1 - \frac{1}{p_i}}$

应用阶乘法筛出逆元(用 $(P-1)!^{-1}$ 逆推),预处理出后一部分前缀积,复杂度 $O(n + T)$

#include <iostream>
#include <cstdio>
#include <cstring>

#define LL long long
#define N 10000010

using namespace std;

int tot, prime[N], inv[N], fac[N], P, prev[N];
bool v[N];

int mul(int a,int b)
{
    return a*(LL)b % (LL)P;
}

int qpow(int x,int n)
{
    int ans = 1;
    for(;n;n>>=1,x = mul(x, x))
        if(n&1) ans = mul(ans, x);
    return ans;
}

void init()
{
    fac[0] = 1;
    int nl = min(N,P);
    for(int i=1;i < nl ;i++) fac[i] = mul(fac[i-1], i);
    int tmp = qpow(fac[nl-1], P-2);
    for(int i=nl-1;i>=1;i--)
    {
        inv[i] = mul(tmp, fac[i-1]);
        tmp  = mul(tmp, i);
    }
}

int main()
{
    int T;
    cin>>T>>P;
    init();
    for(int i=2;i<N;i++)
    {
        if(!v[i]) prime[++tot] = i;
        for(int j=1;i*prime[j]<N;j++)
        {
            v[i*prime[j]] = 1;
            if(i%prime[j]==0) break;
        }
    }
    int j = 1;
    prev[0] = 1;
    for(int i=1;i<N;i++)
    {
        prev[i] = prev[i-1];
        if(j<=tot && prime[j]==i)
        {
            prev[i] += P - mul(prev[i] ,inv[i]);
            if(prev[i] >= P) prev[i] -= P;
            j++;
        }
    }
    int n,m;
    while(T--)
    {
        scanf("%d%d",&n,&m);
        printf("%d\n",mul(fac[n], prev[m]));
    }
    return 0;
}
View Code

常见积性数论函数

$\mu (i)$ :狄里克莱卷积里的逆元函数

当i为若干个不同质数相乘得到,则 $\mu (i) = (-1) ^ {cnt}$ ($cnt$ 表示i中质因数的个数)

不然 $\mu (i) = 0$

1. $\mu (i) = -1$

2. $\mu (tp) = 0$

3. $\mu (tp) = -\mu (t)$

$e (i)$ :判别函数, [i =1],相当于狄里克莱卷积之中的 '1'

$d (i)$ :约数个数,建立辅助函数 $a (i)$ 表示最小质因数的指数

$d(i) = \prod {t_i + 1}, i = p_1^{t_1} p_2^{t_2} ... p_{cnt}^{t_{cnt}}$

1. $d(i) = 2, a(i) = 1$

2. $d(tp) =  \frac{d(t)}{a(t)+1} \times (a(t)+2) , a(tp) = a(t) + 1$

3. $d(tp) = 2 d(t)$

$\sigma (i)$ :约数和

记 $F(p,t) = \frac{1 - p ^ {t + 1}}{1 - p}$

$\sigma (i) = \prod { F(p_i, t_i)  }$

1. $\sigma (i) = i+1$

2. $\sigma (tp) = \frac{\sigma (t)}{ F(p, a(t)) } \times F(p, a(t)+1)$

3. $\sigma (tp) = \sigma (t) (p+1)$

 狄里克莱卷积

首先有两个常用的性质:

$\sum _{d|n} {\phi (d)} = n, \phi \times I = id$

$\sum_{d|n} {\mu (d)} = e(n), \mu \times I = e$

如果 $f, g$ 为积性函数,则有 $f \times g, f \cdot g$ 为积性函数。

小Trick:

$\sum{f( [\frac{n}{i}] )}$ 可以根据 $[\frac{n}{i}]$ 的值分成 $O(\sqrt n)$ 块,并且有 $[\frac{n}{i}]$ 相同的 i 连续。

 例题若干:

1D GCD sum:

$$\sum_{i=1}^n {(n,i)}= \sum_{i=1}^n { \sum_{d|(n,i)}{\phi(d)} } = \sum_{d|n} { [\frac{n}{d}] \phi(d)}$$

2D GCD sum:

$$\sum_{i=1}^n { \sum_{j=1}^m {(i,j)} } = \sum_{i=1}^n{ \sum_{j=1}^m{ \sum_{d|(i,j)} {\phi (d)}  }   } = \sum_{d=1}^n{ \phi (d) [\frac{n}{d}] [\frac{m}{d}] }$$

2D prime count:

$$\sum_{i=1}^n {\sum_{j=1}^m {e((i,j))}} = \sum_{i=1}^n{ \sum_{j=1}^m{ \sum_{d|(i,j)} {\mu (d)}  }   } = \sum_{d=1}^n{ \mu (d) [\frac{n}{d}] [\frac{m}{d}] }$$

1D prime sum:

$$\sum_{1 \leq i \leq n, (n,i) = 1}i = \sum_{i=1}^n { i e((n,i))} = \frac{n}{2}(\mu \times id + \mu \times I) = \frac{n}{2}(\phi + e) = \frac{n}{2} (\phi(n) + e(n))$$

莫比乌斯反演

由于在狄里克莱卷积中 $\mu (x)$ 为 $I(x)$ 的逆函数,这样有,对于 $F = f \times I$, $f = F \times \mu$,即为莫比乌斯反演。

 1 D LCM sum:

$$Ans = \sum_{i=1}^n { [n,i] } = n \sum_{i=1}^n { \frac{i}{(n,i)} } = n \sum_{d|n}{ \sum_{i \leq \frac{n}{d}}{i \cdot e((\frac{n}{d},i))} } = n \sum_{d|n}{ g(\frac{n}{d}) }$$

而$g(n) = \frac{n}{2}(\phi + e)$

代入得$$Ans = \frac{n^2}{2} ( (\phi \times I) + 1)$$

 2 D LCM sum:

$$\sum_{i=1}^n {\sum_{j=1}^m {[i,j]}} = \sum_{d=1}^n { d \times S([\frac{n}{d}], [\frac{m}{d}]) }$$

$$S(n,m) = \sum_{i=1}^m{ \sum_{j=1}^m { ij \cdot e((i,j))} } = \sum_{d=1}^n{\mu (d) d^2 S([\frac{n}{d}])  S([\frac{m}{d}]) }$$

$$S(n) = \frac{n(n+1)}{2}$$

两个部分都根据$\frac{n}{i}$ $O(\sqrt n)$分段,时间复杂度 $O(n)$

#include <iostream>
#include <cstdio>
#include <cstring>

#define LL long long
#define P 20101009LL
#define N 10000010

using namespace std;

int n,m,tot,prime[N/5],mu[N],Sum[N];
bool v[N];

int mul(int a,int b)
{
    return (a * (LL)b) % P;
}

int F(int n,int m)
{
    int j;
    LL ans = 0;
    for(int i=1;i<=n;i=j+1)
    {
        j = min(n/(n/i), m/(m/i));
        ans += (mu[j]-(LL)mu[i-1]+P)%P * (LL)Sum[n/i]%P * (LL)Sum[m/i]%P;
        if(ans>=P) ans -= P;
    }
    return ans;
}

int main()
{
    freopen("nt2011_table.in","r",stdin);
    freopen("nt2011_table.out","w",stdout);
    int n,m;
    cin>>n>>m;
    if(n>m) swap(n,m);
    mu[1] = 1;
    Sum[1] = 1;
    for(int i=2;i<=m;i++)
    {
        Sum[i]=Sum[i-1]+i;
        if(Sum[i]>=P) Sum[i]-=P;
    }
    for(int i=2;i<=n;i++)
    {
        if(!v[i])
        {
            prime[++tot] = i;
            mu[i] = P-1;
        }
        for(int j=1;j<=tot && i*prime[j]<=n;j++)
        {
            v[i*prime[j]] = 1;
            mu[i*prime[j]] = P-mu[i];
            if(i%prime[j]==0)
            {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
    for(int i=1;i<=n;i++) mu[i] = mu[i]*(LL)i%P * (LL)i%P;
    for(int i=1;i<=n;i++)
    {
        mu[i] += mu[i-1];
        if(mu[i]>=P) mu[i] -= P;
    }
    int j;
    LL ans = 0;
    for(int i=1;i<=n;i=j+1)
    {
        j = min(n/(n/i), m/(m/i));
        ans += (Sum[j]-Sum[i-1]+P)%P * F(n/i,m/i)%P;
        if(ans>=P) ans -= P; 
    }
    cout << ans << endl;
}
View Code

记 $f(n) = \frac{1}{n},$,$f = F \times I$

这样 $g = n \cdot F = \mu \cdot id$,这样有$g$为积性函数。

$$Ans = \sum_{i=1}^n {\sum_{j=1}^m { ij \sum_{d|(i,j)}{F(d)} }} = \sum_{d=1}^n{ g(d) d \cdot S([\frac{n}{d}]) S([\frac{m}{d}]) }$$

$g(p) = 1-p$

$g(ip) = g(i)$,$(i,p) = p$,线性筛即可。

posted @ 2017-07-21 12:51  lawyer'  阅读(397)  评论(0编辑  收藏  举报