数论卷积相关

积性函数

如果函数是积性函数,那么只需要知道其在 \(1, p^k\) 处的取值,那么已经完全了解了这个函数。这极大简化了问题。

随便看个例子:求因子和函数 \(\sigma\) 是什么。

首先证明是积性函数。考虑 \(\operatorname{id} * \mathbf 1 = \sigma\),因此是积性函数。

其次考虑其在 \(1,p^k\) 处取值:image

因此可以乘起来就知道了。

接下来再看看欧拉函数是什么。怎么证明积性函数:

image

那是什么就乱证。

逆元,单位元的定义

单位元 \(e\),也叫做幺元。其在一个半群 \((D, \circ)\)(前一个是元素集合,后一个是运算符)中被定义的话,半群被称作幺半群。

某一个元素 \(x\) 的逆元 \(x^{-1}\),意思是 \(x \circ x^{-1} = e\)

例如,
对于 \(\circ = +\)\(e = 0\),因此 \(x + x^{-1} = 0\)
对于 \(\circ = \times\)\(e = 1\),因此 \(x \times x^{-1} = 1\)
对于 \(\circ = \times\)(矩阵乘法),$e = $ 单位矩阵(主对角线是 \(1\) 其他都是 \(0\))。

Dirichlet 卷积

也叫乘法卷积。
对于两个数列 \(\{a_n\}, \{b_n\}\),定义 \(\{c_n\}\)\(a,b\) 做狄利克雷卷积的结果。也称 \(c = a * b\)。那么 \(\forall i, c_i = \sum \limits_{k | i} a_k b_{\frac{i}{k}}\)。朴素地进行一次狄利克雷卷积,时间复杂度为 \(O(n \ln n)\)
性质:
对于两个积性函数 \(f, g\)\(f*g\) 是积性函数。容易证明。(有什么用?积性函数有一些牛逼的筛法和性质)

在此基础上,定义一些特殊函数。

\(\mathbf 1\) 函数:\(\mathbf 1_x = 1\),是完全积性函数。

\(e\) 函数:半群 \((f, *)\) 的单位元。考虑其性质:
\(e * f = f\)
\(x=1\) 时,\(e_1f_1=1\),显然 \(e_1=1\)
\(x\neq 1\) 时,\(e_1f_x + e_?f_?... = 1\),显然 \(e_? = 0\)
因此 \(e = \{1, 0, 0, ..., 0\}\)

\(\mu\) 函数:也叫做莫比乌斯函数。是 \(\mathbf 1\) 函数的逆元。也即,\(\mathbf 1 * \mu = e\)
\(x=1\) 时,\(\mathbf 1_1 \mu_1 = 1\),显然 \(\mu_1 = 1\)
\(x=p\) 时,\(\mathbf 1_1 \mu_p + \mathbf 1_p \mu_1 = 0\),显然 \(\mu_p = -1\)
为了简便,我们发现可以省去 \(\mathbf 1_?\)。接着看看。
\(x=p^k\) 时,\(\mu_1 + \mu_p + \mu_{p^2} + \mu_{p^3} + ...\),那么当 \(k>1\) 的时候 \(\mu_{p^k} = 0\)
\(x=pq\) 时,$\mu_1 + \mu_p + \mu_{q} + \mu_{pq} $,那么 \(\mu_{pq} = 1\)
二项式反演得,\(\mu_{p_1p_2p_3...p_k}=(-1)^k\)
\(x=p_1^{a_1}p_2^{a_2}...p_k^{a_k}\) 时,需要 \(\mu_{有平方因子的数}=0\)
验证一下,确实能对的上。
因此 \(\mu_x = \left\{ \begin{array}{ll} (-1)^k & x 没有平方因子,有 k 个质因数 \\ 0 & x 有平方因子 \end{array} \right. \)

有一个东西是要注意到的。\(\sum \limits_{d | n} f_d\) 等于 \(f *\mathbf 1\)

莫比乌斯反演

\(f * 1 = g, g * \mu = f\),第二个过程就是莫比乌斯反演。

有什么作用?对于某一项的性质可以追踪。例如 \(\mathbf 1_x * \mu_x = e_x\),可以判断 \([x=1]\)

莫比乌斯函数是积性函数,可以通过线性筛求。其中素数赋 \(1\),最小质因子乘上的时候赋 \(0\),否则赋相反数。

POI2007 Zap(BZOJ1101)

image

整除分块即可。这是非常经典的应用。虽然在 \(a = b\) 的时候具有 \(2 \sum φ_i - 1\) 的简便方法,但是这个推法显然是更为能够推广的。

拓展式子

\(\varphi * \mathbf 1 = \operatorname{id}\),其中 \(\operatorname{id}_x = x\)
证明:
首先这三个都是积性函数,因此只需证明对任意 \(p^k\) 都成立,那么对所有正整数均成立。
考虑 \(\varphi_{p^k} = p^{k-1}(p-1)\)
因此 \(\varphi_{p^k} * \mathbf 1 = \sum \limits_{i = 1}^{k} p^{i-1} (p-1) + 1\)

image

得证。

狄利克雷前缀和

更优秀的求 \(a * \mathbf 1\) 的方式。用 \(p\) 进赋值序列的视角看待,是一个高维前缀和。注意 \(1\) 没啥特别的,没有 \(1\) 这一维度。
时间复杂度 \(O(n \log \log n)\),比一般的 \(O(n \log n)\) 要好。

P5495
f(i, 1, cnt) for(int j = p[i]; j <= n; j += p[i]) a[j] += a[j / p[i]];

类似地,可以卷 \(\mu\),也就是前缀和的逆运算。还不用筛。

f(i, 1, cnt) for(int j = n / p[i]; j >= 1; j --) a[j * p[i]] -= a[j];
P2714

gcd 卷积。 \(\sum \limits_{\gcd(i, j) = 1} a_ib_j\)

这个算超集和,就是 FMT。不需要显式的 \(p\) 进赋值序列,只需要直接枚举 \(p\) 即可。

注意卷积里面 \(a,b\) 分别是多少。

最后容斥做的时候一定要推清楚。系数是一个组合数行求和形式。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
//#define cerr if(false)cerr
#define freopen if(false)freopen
#define watch(x) cerr  << (#x) << ' '<<'i'<<'s'<<' ' << x << endl
void cmax(int &x, int y) {if(x < y) x = y;}
void cmin(int &x, int y) {if(x > y) x = y;}
//调不出来给我对拍!
const int v = 10000; 
int p[10010]; bool c[10010]; int cnt; int a[10010], b[5][10010];
void euler() {
    f(i, 2, v) {
        if(!c[i]) {p[++cnt] = i;}
        for(int j = 1; j <= cnt && p[j] * i <= v; j ++) {
            c[p[j] * i] = 1;
            if(i % p[j] == 0) break;
        }
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    //freopen();
    //freopen();
    //time_t start = clock();
    //think twice,code once.
    //think once,debug forever.
    euler(); 
    int n; 
    while(cin >> n) {
        memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); 
        f(i, 1, n) {cin >> a[i]; b[1][a[i]] ++;}
        //对 b 做 gcd 卷积
        f(i, 1, v) b[0][i] = b[1][i];
        f(j, 1, cnt) { //维度
            for(int k = v / p[j]; k >= 1; k --) {
                b[0][k] = b[0][k * p[j]] + b[0][k]; 
            }
        }
        f(i, 1, 3) {
            //FWT
            f(j, 1, v) b[i + 1][j] = b[i][j];
            f(j, 1, cnt) { //维度
                for(int k = v / p[j]; k >= 1; k --) {
                    b[i + 1][k] = b[i + 1][k * p[j]] + b[i + 1][k]; 
                }
            }
            //点值乘法
            f(k, 1, v) b[i + 1][k] *= b[0][k];
            //IFWT
            f(j, 1, cnt) {
                for(int k = 1; k <= v / p[j]; k ++) b[i + 1][k] = b[i + 1][k] - b[i + 1][k * p[j]];
            }
        }
        b[2][1] -= b[1][1]; b[2][1] /= 2;
        b[3][1] -= b[1][1]; b[3][1] -= 6 * b[2][1]; b[3][1] /= 6;
        b[4][1] -= b[1][1]; b[4][1] -= 14 * b[2][1]; b[4][1] -= 36 * b[3][1]; b[4][1] /= 24;
        cout << b[4][1] << endl;
    }
    //time_t finish = clock();
    //cout << "time used:" << (finish-start) * 1.0 / CLOCKS_PER_SEC <<"s"<< endl;
    return 0;
}
/*
2023/x/xx
start thinking at h:mm


start coding at h:mm
finish debugging at h:mm
*/

狄利克雷除法

image

递推,先解出 \(G\),时间复杂度 \(O(n \log n)\),然后卷。
总时间 \(O(n \log n)\)

性质

狄利克雷卷积有交换律和结合律。(这个乱证)

两个积性函数做狄利克雷除法的结果是积性函数。

powerful number 筛

powerful number,是没有非平方因子的数。\(\le n\) 的 powerful number 的规模是 \(O(\sqrt n)\) 的。

image

时间复杂度 \(O(\sqrt n \times t)\)\(t\) 是查询一次 \(g\) 前缀和的时间。

2.2 模拟赛 T2 数论导数

【题意】
image
【分析】
image
怎么求 \(q_d\)\(d \in powerful~number\) 的时候的取值?首先 \(q\) 是积性函数。因此只需要知道 \(q_1\)\(q_{p^k}\) 的取值就可以乘出所有取值。注意 \(k > 1 \or k = 0\) 对所有 \(p\) 都成立。

image

积性函数的性质非常神奇,一定要懂得用。

posted @ 2023-02-03 00:11  OIer某罗  阅读(184)  评论(0编辑  收藏  举报