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

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

F(x)=i1fiix

定义常函数即黎曼函数 ζ(s)=n11ns


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

F×G=ijfigj(ij)x=d1i|dfigdidx

复杂度 O(nlnn)


除法的情况考虑

i|dfigid=hd

首先求出 g1=h1f1,然后对于其余位置有:

gd=hdf1i2,i|dfigdi

复杂度 O(nlogn)


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

考虑

lnF(x)=F(x)F(x)dx

重点在于 F(x)

F(x)=i1filniixF(x)=i1fi1lniix

所以重点就在于 lni,而 lni 在模意义下并没有封闭形式。

考虑没有封闭形式时我们通常用扩域的方式处理:设 pi 表示第 i 个质数,令 ia=lnpa。显然对于任意数字 x=ipiailnx=jajij

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

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

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

F(x)=i1fic(i)ixF(x)=i1fiixc(i)

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

f1=1fd=gd+i2,i|dgifdic(i)

Dirichlet k-th root

快速幂就直接套用 lnexp 即可。

复杂度 O(nlogn)

#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 @   Flying2018  阅读(263)  评论(0编辑  收藏  举报
(评论功能已被禁用)
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示