狄利克雷生成函数学习笔记

首先定义狄利克雷生成函数:

\[F(x)=\sum_{i\geq 1} \frac{f_i}{i^x} \]

定义常函数即黎曼函数 \(\zeta(s)=\sum_{n\geq 1} \frac{1}{n^s}\)


考虑乘法的定义就是狄利克雷卷积:

\[F\times G=\sum_{i}\sum_{j}\frac{f_ig_j}{(ij)^x}\\ =\sum_{d\geq 1}\frac{\sum_{i|d} f_ig_{\frac di}}{d^x}\\ \]

复杂度 \(O(n\ln n)\)


除法的情况考虑

\[\sum_{i|d}f_ig_{\frac{i}{d}}=h_d \]

首先求出 \(g_1=\frac {h_1}{f_1}\),然后对于其余位置有:

\[g_d=\frac {h_d}{f_1}-\sum_{i\geq 2,i|d}f_ig_{\frac di} \]

复杂度 \(O(n\log n)\)


考虑上述两个运算并没有用到生成函数的性质。一般来说,生成函数的一大重要性质就是 \(\ln\)\(\exp\)

考虑

\[\ln F(x)=\int \frac{F'(x)}{F(x)}\text{d} x \]

重点在于 \(F'(x)\)

\[F'(x)=\sum_{i\geq 1} \frac{-f_i\ln i}{i^x}\\ \int F(x)=\sum_{i\geq 1} \frac{-f_i\frac{1}{\ln i}}{i^x} \]

所以重点就在于 \(\ln i\),而 \(\ln i\) 在模意义下并没有封闭形式。

考虑没有封闭形式时我们通常用扩域的方式处理:设 \(p_i\) 表示第 \(i\) 个质数,令 \(\textbf{i}_a=\ln p_a\)。显然对于任意数字 \(x=\sum_i p_i^{a_i}\)\(\ln x=\sum_j a_j\textbf{i}_j\)

考虑到由于任何运算都是在因数之间进行的,故任意时刻 \(\textbf{i}_j\) 的指数一定是正的。故把扩域后的数字当成多元生成函数,就可以直接定义乘法除法。换句话说所有操作的指数部分都是整除的状态下进行的。类似于 \(\frac{4xy+2xy^2+6x^2y}{2+y+3x}=2xy\)。令 \(c(x)\) 表示 \(x\) 所有系数之和。这种情况下一定有 \(c(\frac xy)=\frac{c(x)}{c(y)}\)

注意到 \(\textbf{i}\) 其实本身是没有定义的,所以我们可以大胆猜测最后的结果中一定不带 \(\textbf{i}\),故最后 \(c(x)\) 就是答案。

故我们直接记录系数之和。而对于一个自然数 \(x\)\(c(x)\) 就是其所有因数之和。直接令 \(\ln x=c(x)\) 即可。

\[F'(x)=\sum_{i\geq 1} \frac{-f_ic(i)}{i^x}\\ \int F(x)=\sum_{i\geq 1} \frac{-f_i}{i^xc(i)} \]

考虑 \(\exp\),有 \(G(x)F'(x)=G'(x)\),因为 \(G'(x)\) 相当于每一项乘了 \(c(i)\),可以用类似除法的方式:

\[f_1=1\\ f_d=\cfrac{g'_d+\displaystyle\sum_{i\geq 2,i|d}g'_if_{\frac di}}{c(i)} \]

Dirichlet \(k\)-th root

快速幂就直接套用 \(\ln\)\(\exp\) 即可。

复杂度 \(O(n\log n)\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define N 1000010
#define mod 998244353
#define S(a) ((int)a.size())
#define R(a) a.resize(n+1)
#define il inline
using namespace std;
il int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
il int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
typedef vector<int> poly;
int ksm(int a,int b=mod-2)
{
    int r=1;
    for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) r=1ll*r*a%mod;
    return r;
}
int n,c[N],ci[N];
void init()
{
    c[1]=0;
    for(int i=2;i<=n;i++)
    {
        if(!c[i]) c[i]=1;
        ci[i]=ksm(c[i]);
        for(int j=2;i*j<=n;j++) c[i*j]=c[i]+c[j];
    }
}
poly operator +(poly a,poly b)
{
    R(a);R(b);
    poly c(n+1);
    for(int i=1;i<=n;i++) c[i]=add(a[i],b[i]);
    return c;
}
poly operator -(poly a,poly b)
{
    R(a);R(b);
    poly c(n+1);
    for(int i=1;i<=n;i++) c[i]=dec(a[i],b[i]);
    return c;
}
poly operator *(poly a,int b){for(int i=0;i<S(a);i++) a[i]=1ll*a[i]*b%mod;return a;}
poly operator *(poly a,poly b)
{
    R(a);R(b);
    poly f(n+1);
    for(int i=1;i<=n;i++)
        for(int j=1;i*j<=n;j++) f[i*j]=(f[i*j]+1ll*a[i]*b[j])%mod;
    return f;
}
poly operator /(poly a,poly b)
{
    R(a);R(b);
    poly f(n+1);
    for(int i=1,r=ksm(b[1]);i<=n;i++) f[i]=1ll*a[i]*r%mod;
    for(int i=1;i<=n;i++)
        for(int j=2;i*j<=n;j++) f[i*j]=dec(f[i*j],1ll*f[i]*b[j]%mod)%mod;
    return f;
}
poly Der(poly a){for(int i=1;i<=n;i++) a[i]=1ll*a[i]*c[i]%mod;return a;}
poly Int(poly a){for(int i=1;i<=n;i++) a[i]=1ll*a[i]*ci[i]%mod;return a;}
poly ln(poly a){R(a);return Int(Der(a)/a);}
poly exp(poly a)
{
    poly f=Der(a),d=f;
    d[1]=1;
    for(int i=2;i<=n;i++)
    {
        d[i]=1ll*d[i]*ci[i]%mod;
        for(int j=2;i*j<=n;j++) d[i*j]=add(d[i*j],1ll*f[j]*d[i]%mod)%mod;
    }
    return d;
}
poly ksm(poly a,int k){return exp(ln(a)*k);}
poly f;
int main()
{
    int k;
    scanf("%d%d",&n,&k);
    init();
    R(f);
    for(int i=1;i<=n;i++) scanf("%d",&f[i]);
    f=ksm(f,ksm(k));
    for(int i=1;i<=n;i++) printf("%d ",f[i]);
    return 0;
}
posted @ 2021-04-19 10:34  Flying2018  阅读(342)  评论(0)    收藏  举报