【学习笔记】狄利克雷卷积

基本形式

f , g f,g f,g 函数卷起来写作 f ∗ g ( n ) f * g (n) fg(n),等于 ∑ d ∣ n f ( d ) g ( n d ) \sum_{d \mid n} f (d) g (\frac{n}{d}) dnf(d)g(dn)

性质:

  • f , g f, g f,g 都为(完全)积性函数,那么 f ∗ g f * g fg 也为(完全)积性函数。
  • f ∗ g = g ∗ f f * g = g * f fg=gf (交换律)
  • f ∗ g ∗ q = f ∗ ( g ∗ q ) f * g * q = f * (g * q) fgq=f(gq) (结合律)

例题

一、 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)=i1ii2i1i3i2ikik1fik=i1ii2i1i3i21(ik1n)ikik1fik1(iki)=1kf(i)=i=digk1(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)=uv=n2fr1u+fr1v=unfr1u=unfr1u1(un)

证明 f r ( n ) f_r(n) fr(n) 是一个积性函数。

归纳法,假设 f r − 1 ( n ) f_{r - 1}(n) fr1(n) 是一个积性函数。

则:

∵ f r − 1 ( n ) , 1 ( n ) \because f_{r - 1}(n),1 (n) fr1(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=0kfr1(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;
}
posted @ 2022-02-11 17:50  C2022lihan  阅读(22)  评论(0编辑  收藏  举报