狄利克雷卷积

h(n)=(fg)(n)=i|nf(i)g(ni)=ab=xf(a)g(b)h=fgfg=gfab(fg)h=f(gh)f(g+h)=fg+fhfε=ffgfgf=gfh=ghh(1)0fg=εfg

常见卷积公式

ε=μ1d=11σ=id1φ1=id

积性函数线性筛

利用欧拉筛的方法,显然容易线性筛出任何积性函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void getf()
{
f[1]=;
rep(i,2,n)
{
if (!notprime[i]) prime[++tot]=i,f[i]=(式子1);
for (int j=1;j<=tot&&i*prime[j]<=n;j++)
{
notprime[i*p[j]]=1;
if (i%prime[j]==0)
{
f[i*prime[j]]=(式子2);
break;
}
f[i*prime[j]]=(式子3);
}
}
}

式子1 质数,式子2 质数prime[j]的指数增加了一,式子3 互质

比如筛莫比乌斯函数时,式子1为-1,式子2为0,式子3为-f[i]

筛欧拉函数时,式子1为i-1,式子2为f[i]*prime[j],式子3为phi[i]*(prime[j]-1)

数论分块

含有ni的求和式,如ni=1nif(i),容易发现ni的取值只有n种。设当前值的左界为l,有界为r,则一个方便的跳l、r的方式是l=r+1,r=n/(n/l)。如果f(x)能用求和公式表示,那么整个式子的值就能在O(n)的时间复杂度内完成

做了一道模板题Luogu P2261,因为太显然了,就不单独发blog,这里也不贴代码了。

二维数论分块

min(n,m)i=1nimi

只是把跳n次变成2n次罢了,找n和m的跳跃点中最近的位置跳即可。

莫比乌斯反演

f(n)=d|ng(d)g(n)=d|nμ(d)f(nd)f=g1g=fμ

由前文狄利克雷卷积部分知识,显然。

如何应用

场景一

g(i)f(i)=d|ig(d)f(i)=d|ig(d)g(i)=d|if(id)μ(d)

场景二

g(i)f(i)=nid=1g(di)f(i)=nid=1g(di)g(i)=nid=1f(di)μ(d)

技巧

等价变换:改变枚举顺序(内层外移)、变量替换等技巧

线性筛:线性处理各种信息

数论分块:重要工具

例1

经过转化之后,问题的核心是
nki=1mkj=1(gcd(i,j)==1)

解:

看到==1这种东西,首先想到单位元函数
=nki=1mkj=1ε(gcd(i,j))=nki=1mkj=1d|gcd(i,j)μ(d)  =minnk,mkd=1μ(d)mkdnkd
其中推导的最后一步更换了枚举的变量。可以发现,倒数第二个式子中,对于每个d,当d|id|jμ(d)都会被加一次,因此可以得到最终的式子。

而最终的式子显然可以在预处理出莫比乌斯函数的前缀和后通过上面提到的二维数论分块的思路来快速解决

例2


ni=1mj=1gcd(i,j)

解:

利用常见卷积的公式,
=ni=1mj=1d|gcd(i,j)φ(d)=d=1φ(d)ndmd
接下来处理和例1相同

例3 SPOJ5971 LCMSUM

ni=1lcm(i,n)

3e5组询问,n范围1e6

解:

=ni=1ingcd(i,n)=d|nni=1ind[gcd(i,n)==d]=nd|nndi=1id[gcd(i,nd)==1],i=nd|ndi=1i[gcd(i,d)==1],dnd=nd|ndφ(d)+[d==1]2,φ=n2(d|nφ(d)d+1),

至此可以得到O(n)预处理出欧拉函数,O(n)回答询问的方法。但是这样会TLE

考虑将答案函数预处理:显然可以在调和级数复杂度下做出来。总复杂度O(nlgn+T)

通过推导可以发现,d|nφ(d)d是个积性函数,可以线性预处理,因此可以做到O(n+T),具体证明待补

例4

ni=1mj=1lcm(i,j)

解:

=ni=1mj=1ijgcd(i,j)=ni=1mj=1ijd[gcd(i,j)==d]=nd=1ndi=1mdj=1ijd[gcd(i,j)==1]=nd=1dndi=1imdj=1jk|gcd(i,j)μ(k)=nk=1k2μ(k)nd=1dndki=1imdkj=1jf(x)=xi=1i,T=nk=nT=1d|TT2d2dμ(Td)f(nT)f(mT)=nT=1f(nT)f(mT)Td|Tdμ(d)F(x)=d|Tdμ(d)O(n)

例5 SDOI2015 约数个数和

ni=1mj=1d(ij)

解:

d(ij)=d|id|j[gcd(i,j)==1]=ni=1mj=1d|id|j[gcd(i,j)==1]=ni=1mj=1id=1μ(d)idjd=nd=1μ(d)ni=1idmj=1jd

例6 SDOI2017 数字表格

ni=1mj=1fib(gcd(i,j))n,m106,T1000,fib(0)=0

解:

只1是把问题放到了指数上罢了。斐波那契数列显然和数论要用的这些没什么大关系,所以先常规操作:
=ni=1mj=1f(d)[gcd(i,j)=d]=d=1ndi=1mdj=1f(d)[gcd(i,j)=1]=d=1ndi=1mdj=1k|gcd(i,j)f(d)μ(k)=d=1k=1ndki=1mdkj=1f(d)μ(k)=nT=1d|Tf(d)nTmTμ(Td)=nT=1(d|Tf(d)μ(Td))nTmT

例7 BZOJ4407 于神之怒加强版

ni=1mj=1gcd(i,j)kn,m5106,T2000

解:

=nd=1ndi=1mdj=1dk[gcd(i,j)=1]=nT=1mTnTd|Tdkμ(Td),σkμ线

例8 BZOJ2820 YY的GCD

ni=1mj=1[gcd(i,j)prime]n,m107

解:

=nT=1nTmTk|T,kprimeμ(Tk)np=1np[pprime],nlgn,O(nlgn)O(n)

例9 HDU4944 FSF’s game

ni=1nj=id|i,jijgcd(id,jd)T=500000,n500000

解:

首先看到这个gcd在分母上这个样子,很难受,同时形式很像是lcm,考虑转化
=ni=1nj=id|gcd(i,j)dlcm(i,j)=nd=1d2ndi=1ndj=ilcm(i,j)ij=nd=1d2ndi=1ij=1lcm(i,j)3=nd=1d2ndi=1i2(k|ikφ(k)+1)iO(nlgn)indi=1i2(k|ikφ(k)+1)f(nd),=nd=1d2f(nd),,500000f

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
const int maxN=555555,maxn=500000;
int n,T,phi[maxN],prime[maxN],tot;
bool notprime[maxN];
void getf()
{
phi[1]=1;
notprime[1]=true;
rep(i,2,maxn)
{
if (!notprime[i]) prime[++tot]=i,phi[i]=i-1;
for (int j=1;j<=tot&&i*prime[j]<=maxn;j++)
{
notprime[i*prime[j]]=1;
if (i%prime[j]==0)
{
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
LL f[maxN];
unsigned g[maxN];
int main()
{
getf();
rep(i,1,maxn)
for (int j=i;j<=maxn;j+=i) f[j]+=(LL)i*phi[i];
rep(i,1,maxn) f[i]=f[i-1]+i*(f[i]+1)/2LL;
rep(i,1,maxn) for (LL j=1;j*i<=maxn;j++)
{
g[j*i]+=(LL)i*i*f[j];
if (i*(j+1)<=maxn) g[i*(j+1)]-=(LL)i*i*f[j];
}
rep(i,1,maxn) g[i]+=g[i-1];
read(T);
int kase=0;
while (T--)
{
read(n);
printf("Case #%d: %u\n",++kase,(unsigned)g[n]);
}
return 0;
}

例10 HDU6428 Calculate

ai=1bj=1ck=1φ(gcd(i,j2,k3))

解:

=ai=1bj=1ck=1d|gcd(i,j2,k3)(φμ)(d)=d=1(φμ)(d)ai=1bj=1ck=1[d|gcd(i,j2,k3)]=d=1(φμ)(d)ai=1[d|i]bj=1[d|j2]ck=1[d|k3]φμ线kdxi=1[d|ik]d|ikdjprime[j]a[j]k|ixi=1[d|ik]=xjprime[j]a[j]kf(d)线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
void get(const unsigned &n)
{
notprime[1]=true;
mp[1]=1;f2[1]=1;f3[1]=1;
for (unsigned i=2;i<=n;i++)
{
if (!notprime[i])
{
prime[++tot]=i;
mp[i]=i-2;
f2[i]=f3[i]=i;
cnt[i]=1;
}
for (unsigned j=1;j<=tot&&i*prime[j]<=n;j++)
{
unsigned now=i*prime[j];
notprime[now]=true;
if (i%prime[j]==0)
{
cnt[now]=cnt[i]+1;
unsigned temp=i/prime[j];
if (temp%prime[j]) mp[now]=mp[temp]*sqr(prime[j]-1);
else mp[now]=mp[i]*prime[j];
f2[now]=f2[i]*(cnt[now]&1?prime[j]:1);
f3[now]=f3[i]*(cnt[now]%3==1?prime[j]:1);
break;
}
cnt[now]=1;
mp[now]=mp[i]*mp[prime[j]];
f2[now]=f2[i]*f2[prime[j]];
f3[now]=f3[i]*f3[prime[j]];
}
}
}//用unsigned是因为这道题的模数