积性函数&线性筛&欧拉函数&莫比乌斯函数&因数个数&约数个数和

时间:2022-10-09 16:46:55

只会搬运YL巨巨的博客

积性函数

定义

积性函数:对于任意互质的整数a和b有性质f(ab)=f(a)f(b)的数论函数。

完全积性函数:对于任意整数a和b有性质f(ab)=f(a)f(b)的数论函数

性质

  • 两个积性函数的狄利克雷卷积仍为积性函数。
  • 若积性函数满足 \(f(n^p)=f^p(n)\)则它一定是完全积性函数。因为一个数可以唯一分解,则它一定可以表示成质数相乘的形式;因为他时积性函数所以,\(f(\prod_{i=1}^{n}p_i)=\prod _{i=1}^{n}f(p_i)\),又因为满足上面的式子,所以一定为积性函数。
  • 积性函数值都可以线性筛(我也不知道为什么)

常见的积性函数和筛法

欧拉函数

首先积性函数先分解,分解成质数的乘积。这样你每次都是用质数乘以当前的数筛到下一个数,得到下一个数的函数值。

而euler函数是积性函数,不是完全积性函数。所以在当前枚举到的数的时候要分两种情况讨论:

case1:当\(i\%prime[j]!=0\)时,这个时候显然两个数互质,可以直接相乘筛到下一个数。

case2: 当\(i\%prime[j]==0\)这样显然不能直接相乘了,但我们考虑,对i的每个因子f[x],都可以表示出\(f[x]*k,k<=prime[j]\)这个prime[j] *i的因子。所以在这种情况下\(phi[i*prime[j]]=phi[i]*prime[j];\)

int is[maxn],phi[maxn],prime[maxn],n,cnt;
void euler()
{
is[1]=1;phi[1]=1;
for(int i=1;i<=n;i++)
{
if(!is[i]){prime[++cnt]=i;phi[i]=i-1;}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
{
is[prime[j]*i]=1;
if(i%prime[j]){phi[i*prime[j]]=phi[i]*(prime[j]-1);}
else{phi[i*prime[j]]=prime[j]*phi[i];break;}
}
}
}

莫比乌斯函数

一样拆成质数相乘的形式,但是要注意莫比乌斯函数只有在质因子个数为奇数的时候答案才会为-1或+1,所以对每个质因子只筛一次。

void mobius()
{
is[1]=1;mu[1]=1;
for(int i=1;i<=n;i++)
{
if(!is[i]){prime[++cnt]=i;mu[i]=-1;}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
{
is[prime[j]*i]=1;
if(!(i%prime[j]))break;
mu[i*prime[j]]=-mu[i];
}
}
}

因数个数和

还是拆成素数积的形式。只是再记录一个最小质因子的指数就可以了。为什么是最小的?因为每次我们筛数的时候,它总是被它最小的质因子先筛到,而我们知道i的约数,又知道它最小的质因子的个数,那么i*prime[j]肯定是可以算出来了。一样分情况讨论。

当i是质数的时候,它的约数就是1和它本身。

当i%prime[j]==0的时候,先除掉它原来最小质因子对约数的贡献,再乘上最小质因子个数加1,就是i×prime[j]的约数个数了。

当i%prime[j]!=0的时候,这个时候枚举到的这一个质数是原来i中没有的,那它的贡献一定是2,所以在i的约数上乘以二就可以了。

int is[maxn],fac[maxn],prime[maxn],n,cnt,pre[maxn];
void factor()
{
is[1]=1;fac[1]=1;
for(int i=1;i<=n;i++)
{
if(!is[i]){prime[++cnt]=i;fac[i]=2;pre[i]=1;}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
{
is[prime[j]*i]=1;
if(i%prime[j])
{
fac[i*prime[j]]=2*fac[i];
pre[i*prime[j]]=1;
}
else
{
pre[i*prime[j]]=pre[i]+1;
fac[i*prime[j]]=fac[i]/(pre[i]+1)*(pre[i]+2);
break;
}
}
}
}

因数和

思考一下发现要求的答案其实就是\(ans_x=\prod_{p|x,p\in prime}\sum_{j=1}^{k_p}p^j\)

那么我们线性筛的时候,由于写成可以写成\(\sigma=id*e\)也就是积性函数和积性函数积的形式,那么可以利用积性函数的性质,然后再记录一个最小质因子的指数次幂和最质因子指数幂的和,即\(\sum_{j=1}^{k_p}p^j\)

就可以线性筛了.

int sig[maxn],sum[maxn],pre[maxn];
//约数的和/最小质因子指数次幂和/最小质因子的指数次幂
int prime[maxn],is[maxn],p[maxn],cnt;
void init(int n)
{
sig[1]=1;is[1]=1;
for(int i=2;i<=n;i++)
{
if(!is[i])
{
prime[++cnt]=i;
sig[i]=i+1,sum[i]=i+1,pre[i]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=n;j++)
{
is[prime[j]*i]=1;
if(i%prime[j])
{
sig[i*prime[j]]=sig[i]*sig[prime[j]];
sum[i*prime[j]]=prime[j]+1;
pre[i*prime[j]]=prime[j];
}
else
{
pre[i*prime[j]]=prime[j]*pre[i];
sum[i*prime[j]]=sum[i]+pre[i*prime[j]];
sig[i*prime[j]]=sig[i]/sum[i]*sum[i*prime[j]];
break;
}
}
}
}