【学习笔记】狄利克雷卷积
基本形式
f , g f,g f,g 函数卷起来写作 f ∗ g ( n ) f * g (n) f∗g(n),等于 ∑ d ∣ n f ( d ) g ( n d ) \sum_{d \mid n} f (d) g (\frac{n}{d}) ∑d∣nf(d)g(dn)
性质:
- 若 f , g f, g f,g 都为(完全)积性函数,那么 f ∗ g f * g f∗g 也为(完全)积性函数。
- f ∗ g = g ∗ f f * g = g * f f∗g=g∗f (交换律)
- f ∗ g ∗ q = f ∗ ( g ∗ q ) f * g * q = f * (g * q) f∗g∗q=f∗(g∗q) (结合律)
例题
一、 C l a r k e a n d m a t h Clarke \ and \ math Clarke and math
g i = ∑ i 1 ∣ i ∑ i 2 ∣ i 1 ∑ i 3 ∣ i 2 ⋯ ∑ i k ∣ i k − 1 f i k = ∑ i 1 ∣ i ∑ i 2 ∣ i 1 ∑ i 3 ∣ i 2 ⋯ 1 ( n i k − 1 ) ∑ i k ∣ i k − 1 f i k ⋅ 1 ( i i k ) = 1 k ∗ f ( i ) g 0 ( i ) = i g k ( i ) = ∑ d ∣ i g k − 1 ( d ) ∗ f ( n d ) \begin{aligned} g_i &= \sum_{i_1∣i}\sum_{i_2∣i1}\sum_{i_3∣i2}⋯\sum_{i_k∣i_{k−1}}f_{i_k} \\ &= \sum_{i_1∣i}\sum_{i_2∣i_1}\sum_{i_3∣i_2}⋯ 1(\frac{n}{i_{k - 1}}) \sum_{i_k∣i_{k−1}} f_{i_k} \cdot 1(\frac{i}{i_k}) \\ &= 1 ^ k * f (i) \\ g_0 (i) &= i \\ g_k (i) &= \sum_{d \mid i} g_{k - 1} (d) * f (\frac{n}{d}) \end{aligned} gig0(i)gk(i)=i1∣i∑i2∣i1∑i3∣i2∑⋯ik∣ik−1∑fik=i1∣i∑i2∣i1∑i3∣i2∑⋯1(ik−1n)ik∣ik−1∑fik⋅1(iki)=1k∗f(i)=i=d∣i∑gk−1(d)∗f(dn)
//author : LH ——Who just can eat S??t
//worship WJC ——Who can f??k tourist up and down and loves 周歆恬
//worship YJX ——Who can f??k WJC up and down
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define fi first
#define se second
#define db double
#define LL long long
#define ULL unsigned long long
#define PII pair <int, int>
#define MP(x,y) make_pair (x, y)
#define rep(i,j,k) for (int i = (j); i <= (k); ++i)
#define per(i,j,k) for (int i = (j); i >= (k); --i)
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
template <typename T>
void read (T &x) {
x = 0; T f = 1;
char ch = getchar ();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar ();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar ();
}
x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... args) {
read (x); read (args...);
}
char For_Print[25];
template <typename T>
void write (T x) {
if (x == 0) { putchar ('0'); return; }
if (x < 0) { putchar ('-'); x = -x; }
int poi = 0;
while (x) {
For_Print[++poi] = x % 10 + '0';
x /= 10;
}
while (poi) putchar (For_Print[poi--]);
}
template <typename T>
void print (T x, char ch) {
write (x); putchar (ch);
}
const LL Mod = 1e9 + 7;
LL square (LL x) { return (x * x) % Mod; }
void DEL (LL &x, LL y) { ((x -= y) < 0) && (x += Mod); }
void ADD (LL &x, LL y) { ((x += y) >= Mod) && (x -= Mod); }
const int Maxn = 1e5;
int t, n, k;
vector <int> d[Maxn + 5];
void Euler () {
rep (i, 1, Maxn)
for (int j = i; j <= Maxn; j += i)
d[j].push_back (i);
}
struct Fold {
int n;
LL f[Maxn + 5];
Fold () { n = 0; memset (f, 0, sizeof f); f[1] = 1; }
};
Fold operator * (Fold x, Fold y) {
Fold res; res.n = x.n; res.f[1] = 0;
rep (i, 1, res.n)
for (auto j : d[i])
ADD (res.f[i], x.f[j] * y.f[i / j] % Mod);
return res;
}
Fold quick_pow (Fold x, int y) {
Fold res; res.n = x.n;
while (y) {
if (y & 1) res = res * x;
x = x * x; y >>= 1;
}
return res;
}
int main () {
// freopen ("D:\\lihan\\1.in", "r", stdin);
// freopen ("D:\\lihan\\1.out", "w", stdout);
Euler ();
read (t);
while (t--) {
read (n, k);
Fold f, tmp; f.n = tmp.n = n;
rep (i, 1, n) read (f.f[i]);
rep (i, 1, n) tmp.f[i] = 1;
f = f * quick_pow (tmp, k);
rep (i, 1, n) {
print (f.f[i], ' ');
}
putchar ('\n');
}
return 0;
}
二、 B a s h P l a y s w i t h F u n c t i o n s Bash \ Plays \ with \ Functions Bash Plays with Functions
f r ( n ) = ∑ u ⋅ v = n f r − 1 u + f r − 1 v 2 = ∑ u ∣ n f r − 1 u = ∑ u ∣ n f r − 1 u ⋅ 1 ( n u ) \begin{aligned} f_r(n) &= \sum_{u \cdot v = n} \frac{f_{r - 1} u + f_{r - 1} v}{2} \\ &= \sum_{u \mid n} f_{r - 1} u \\ &= \sum_{u \mid n} f_{r - 1} u \cdot 1 (\frac{n}{u}) \end{aligned} fr(n)=u⋅v=n∑2fr−1u+fr−1v=u∣n∑fr−1u=u∣n∑fr−1u⋅1(un)
证明 f r ( n ) f_r(n) fr(n) 是一个积性函数。
归纳法,假设 f r − 1 ( n ) f_{r - 1}(n) fr−1(n) 是一个积性函数。
则:
∵
f
r
−
1
(
n
)
,
1
(
n
)
\because f_{r - 1}(n),1 (n)
∵fr−1(n),1(n) 是积性函数。
∴
f
r
(
n
)
\therefore f_r (n)
∴fr(n) 是积性函数。
又因为 f 0 ( n ) = 2 k ( n = ∏ i k p i q i ) f_0(n) = 2^k(n = \prod_{i}^{k} p_i^{q_i}) f0(n)=2k(n=∏ikpiqi) 是积性函数。
得证。
f
r
(
p
k
)
=
∑
i
=
0
k
f
r
−
1
(
p
i
)
f_r(p^k) = \sum_{i = 0}^k f_{r - 1}(p^i)
fr(pk)=∑i=0kfr−1(pi)
f
0
(
p
k
)
=
2
f_0(p^k) = 2
f0(pk)=2
我们观察到一个性质: f r ( p k ) f_r(p^k) fr(pk) 的取值只与 k , r k,r k,r 有关。
所以我们可以先跑一遍,预处理出 r = 0 r = 0 r=0 ~ 1 e 6 1e6 1e6, k = 0 k = 0 k=0 ~ l o g 2 ( 1 e 6 ) log_2 (1e6) log2(1e6) 时, f r ( p k ) f_r (p^k) fr(pk) 的取值。
然后求 f r ( n ) f_r(n) fr(n) 时就质因数分解,乘起来就好了。
//author : LH ——Who just can eat S??t
//worship WJC ——Who can f??k tourist up and down and loves 周歆恬
//worship YJX ——Who can f??k WJC up and down
#include <cmath>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define fi first
#define se second
#define db double
#define LL long long
#define ULL unsigned long long
#define PII pair <int, int>
#define MP(x,y) make_pair (x, y)
#define rep(i,j,k) for (int i = (j); i <= (k); ++i)
#define per(i,j,k) for (int i = (j); i >= (k); --i)
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
template <typename T>
void read (T &x) {
x = 0; T f = 1;
char ch = getchar ();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar ();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar ();
}
x *= f;
}
template <typename T, typename... Args>
void read (T &x, Args&... args) {
read (x); read (args...);
}
char For_Print[25];
template <typename T>
void write (T x) {
if (x == 0) { putchar ('0'); return; }
if (x < 0) { putchar ('-'); x = -x; }
int poi = 0;
while (x) {
For_Print[++poi] = x % 10 + '0';
x /= 10;
}
while (poi) putchar (For_Print[poi--]);
}
template <typename T>
void print (T x, char ch) {
write (x); putchar (ch);
}
const LL Mod = 1e9 + 7;
LL square (LL x) { return (x * x) % Mod; }
void DEL (LL &x, LL y) { ((x -= y) < 0) && (x += Mod); }
void ADD (LL &x, LL y) { ((x += y) >= Mod) && (x -= Mod); }
const int Maxn = 1e6;
const int Maxk = 20;
int q, op, n;
int cnt, primes[Maxn + 5];
int num[Maxn + 5], px[Maxn + 5];
bool vis[Maxn + 5];
void Euler () {
rep (i, 2, Maxn) {
if (vis[i] == 0) {
num[i] = 1;
px[i] = i;
primes[++cnt] = i;
}
rep (j, 1, cnt) {
if (primes[j] > Maxn / i) break;
vis[primes[j] * i] = 1;
px[i * primes[j]] = primes[j];
if (i % primes[j] == 0) {
num[i * primes[j]] = num[i];
break;
}
num[i * primes[j]] = num[i] + 1;
}
}
}
LL f[Maxn + 5][Maxk + 5];
void Init () {
f[0][0] = 1; rep (j, 1, Maxk) f[0][j] = 2;
rep (i, 1, Maxn) {
f[i][0] = 1;
rep (j, 1, Maxk)
f[i][j] = (f[i][j - 1] + f[i - 1][j]) % Mod;
}
}
int main () {
//freopen ("D:\\lihan\\1.in", "r", stdin);
//freopen ("D:\\lihan\\1.out", "w", stdout);
Euler ();
Init ();
read (q);
while (q--) {
read (op, n);
if (op == 0) {
print (1ll << num[n], '\n');
}
else {
LL res = 1;
while (n != 1) {
int p = px[n], q = 0;
while (n % p == 0) {
q++;
n /= p;
}
res = res * f[op][q] % Mod;
}
print (res, '\n');
}
}
return 0;
}