狄利克雷生成函数学习笔记
首先定义狄利克雷生成函数:
定义常函数即黎曼函数 \(\zeta(s)=\sum_{n\geq 1} \frac{1}{n^s}\)
考虑乘法的定义就是狄利克雷卷积:
复杂度 \(O(n\ln n)\)。
除法的情况考虑
首先求出 \(g_1=\frac {h_1}{f_1}\),然后对于其余位置有:
复杂度 \(O(n\log n)\)。
考虑上述两个运算并没有用到生成函数的性质。一般来说,生成函数的一大重要性质就是 \(\ln\) 和 \(\exp\)。
考虑
重点在于 \(F'(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)\) 即可。
故
考虑 \(\exp\),有 \(G(x)F'(x)=G'(x)\),因为 \(G'(x)\) 相当于每一项乘了 \(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;
}

浙公网安备 33010602011771号