狄利克雷生成函数

注意本文中用的字母可能和其他博客中有区别。

黎曼zeta函数(zeta(x)=sum_{nge 1} frac{1}{n^x})

手写时本人喜欢写成(z)(因为(zeta)太难写),但是在博客中还是正式点吧。


参考资料:

https://zhuanlan.zhihu.com/p/50817119

https://blog.csdn.net/luositing/article/details/109204796


形式

狄利克雷生成函数(DGF)形式:

[F(x)=sum_{nge 1}frac{f_n}{n^x}。 ]

以下默认(nge 1,nin Z)

不难发现在这个形式下,如果有(H(x)=F(x)G(x)),那么有(h_n=sum_{d|n} f_dg_{frac{n}{d}}),也就是说(h)(f,g)的狄利克雷卷积。


常用数论函数的DGF

(forall n,f_n=1)时,(F(x)=zeta(x))

根据数论函数的基本性质,可以得到

[zeta(x)=prod_p1+p^{-x}+p^{-2x}+dots=prod_pfrac{1}{1-p^{-x}} ]

(f_n=mu(n))时:根据(mu)的定义可得(F(x)=prod_p1-p^{-x})。于是有(F(x)=frac{1}{zeta(x)})

(f_n=n)时:(F(x)=prod_psum_{ige 0}frac{p^i}{p^{ix}}=prod_pfrac{1}{1-p^{-(x-1)}}=zeta(x-1))

(f_n=phi(n))时:(F(x)=prod_p 1+frac{p-1}{p}sum_{ige 1}frac{1}{p^{i(x-1)}}=prod_pfrac{1-p^{-x}}{1-p^{-(x-1)}}=frac{zeta(x-1)}{zeta(x)})

(f_n=sigma_0(n))时:(F(x)=zeta^2(x))

(f_n=sigma_1(n))时:(F(x)=zeta(x)zeta(x-1))

通过这些东西,可以很直观地发现一些性质,什么(I*mu=e)(I*phi=id)(sigma_0*phi=sigma_1)之类的。


DGF的运算

加减不说,乘法朴素(O(nln n)),用类似高维前缀和的方法好像可以做到(O(nln ln n))

除法:假如有(H(x)=F(x)G(x)),已知(H(x),F(x)),则有(h_n=sum_{d|n,d>1}f_dg_{frac{n}{d}}+f_1g_n),移项得到(g_n)。时间(O(nln n))

求导、积分:

[(frac{f_n}{n^x})'=-ln nfrac{f_n}{n^x}\ int frac{f_n}{n^x}dx=-frac{1}{ln n}frac{f_n}{n^x} ]

(ln n)似乎不好处理。注意到求导和积分往往是成对存在的,不妨找个(ln n)的替代品。定义(c(n))表示(n)的可重质因子个数,用它来替代。这个函数也满足(ln)的部分性质:(c(1)=0,c(ab)=c(a)+c(b))

它好像没有复刻(ln)的全部性质,为什么是对的?以下谈谈本人的感性理解:

当然如果有高深的高等数学知识可以略过

我认为这个疑问都来自于不同质数之间的关系,比如(ln 2 eq ln 3),然而这里(c(2)=c(3)=1)

但是其实可以把每个质数看成一个维度,其指数为在这一维上的坐标,于是每个数都相当于无限维空间中的一个点。

我们可以把所有数重标号一下,把质因子(2)全部换成(3),把质因子(3)全部换成(2),相当于两个维度换一下。如果(ln 2 eqln 3)对求导积分之后的结果有影响,不符合对称性,矛盾。

所以并不需要满足(ln 2 eq ln 3)

于是变成这样:

[(frac{f_n}{n^x})'=c(n)frac{f_n}{n^x}\ int frac{f_n}{n^x}dx=frac{1}{c(n)}frac{f_n}{n^x} ]

(ln)(ln F(x)=int frac{F'(x)}{F(x)}dx)

(exp):设(G(x)=e^{F(x)}),则(G'(x)=F'(x)G(x))。把式子拆开,用类似除法的方式做就行了。


例题

PE639(题解):https://www.cnblogs.com/jz-597/p/14402383.html

LOJ6713. 「EC Final 2019」狄利克雷 k 次根 加强版。下面贴代码:

using namespace std;
#include <bits/stdc++.h>
#define N 1000005
#define mo 998244353
#define ll long long
ll qpow(ll x,ll y=mo-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
int n,k;
ll g[N],f[N];
int p[N],np;
bool inp[N];
int c[N],inv[N];
void init(){
	c[1]=0;
	for (int i=2;i<=n;++i){
		if (!inp[i])
			p[++np]=i,c[i]=1;
		for (int j=1;j<=np && i*p[j]<=n;++j){
			inp[i*p[j]]=1;
			c[i*p[j]]=c[i]+1;
			if (i%p[j]==0)
				break;
		}
	}
	inv[1]=1;
	for (int i=2;i<=n;++i)
		inv[i]=(ll)(mo-mo/i)*inv[mo%i]%mo;
}
void check(ll h[],ll f[],ll g[]){
	static ll t[N];
	for (int i=1;i<=n;++i)
		for (int j=1;i*j<=n;++j)
			(t[i*j]+=f[i]*g[j])%=mo;
	for (int i=1;i<=n;++i)
		if (t[i]!=h[i]){
			printf("****
");
			exit(0);
		}
}
void getdiv(ll h[],ll f[],ll g[]){
	static ll d[N];
	memset(d,0,sizeof(ll)*(n+1));
	ll t=qpow(g[1]);
	for (int i=1;i<=n;++i){
		d[i]=(d[i]+mo+f[i])*t%mo;
		for (int j=2;i*j<=n;++j)
			(d[i*j]-=d[i]*g[j])%=mo;
	}
	memcpy(h,d,sizeof(ll)*(n+1));
	check(f,g,h);
}
void getln(ll f[],ll g[]){
	static ll g_[N],_f[N];
	for (int i=1;i<=n;++i)
		g_[i]=g[i]*c[i]%mo;
	getdiv(_f,g_,g);
	f[1]=0;
	for (int i=2;i<=n;++i)
		f[i]=_f[i]*inv[c[i]]%mo;
}
void getexp(ll g[],ll f[]){
	static ll d[N];
	memset(d,0,sizeof(ll)*(n+1));
	assert(f[1]==0);
	d[1]=1;
	for (int j=2;j<=n;++j)
		(d[j]+=c[j]*f[j])%=mo;
	for (int i=2;i<=n;++i){
		d[i]=d[i]*inv[c[i]]%mo;
		for (int j=2;i*j<=n;++j)
			(d[i*j]+=c[j]*f[j]%mo*d[i])%=mo;
	}
	memcpy(g,d,sizeof(ll)*(n+1));
}
void getpow(ll h[],ll g[],ll t){
	static ll d[N];
	getln(d,g);
	for (int i=1;i<=n;++i)
		d[i]=d[i]*t%mo;
	getexp(h,d);
}
int main(){
//	freopen("in.txt","r",stdin);
	scanf("%d%d",&n,&k);
	init();
	for (int i=1;i<=n;++i)
		scanf("%lld",&g[i]);
	getpow(f,g,qpow(k));
	for (int i=1;i<=n;++i)
		printf("%lld ",f[i]);
//	printf("
");
//	getpow(g,f,k);
//	for (int i=1;i<=n;++i)
//		printf("%lld ",g[i]);
//	printf("
");
	return 0;
}
原文地址:https://www.cnblogs.com/jz-597/p/14403977.html