神犇的博客:浅谈一类积性函数的前缀和
线性筛法
//线性筛法求质数。
memset(mark,0,sizeof(mark));
pt=0;
for(int i=2;i<=N;i++)
{
if(!mark[i]){
prime[pt++]=i;
mark[i]=i;
}
for(int j=0,u=dmin(mark[i],N/i);j
marki 表示 i,除 1 以外的最小因子。
primei 维护质数序列。
保证 1~n 内的每一个合数被且只被除1外最小的因子筛过一次,对于当前处理到的 i 枚举小于 marki 的所有质数,将后面的数筛过一遍。时间复杂度 O(n) 。
证明正确性:每一个合数被且只被除1外最小的因子筛过一次。
设合数 P=p1^k1 × p2^k2 × p3^k3 × … × pn^kn
其中 p1,p2,p3...pn 为质数,且 p1<p2<p3...<pn ; k1,k2,k3...kn 为正整数。
若P不是被 P’=p1^(k1-1) × p2^k2 × p3^k3 × … × pn^kn 经过 p1 筛到,
则任意一个除去一个其他因子 pj 得到的数都只能枚举到 p1 。由已知条件, pj>p1 ,则无法筛到P。
积性函数
1.定义。若 f(n) 是积性函数,则当 gcd(a,b)=1时,f(a×b)=f(a)×f(b) 。
若 f(a×b)=f(a)×f(b) ,无限制条件,则 f(n) 被成为完全积性函数。
2.性质。
1) gcd(a,b)=1时,f(a×b)=f(a)×f(b)
2) f(1)=1
欧拉函数
1.定义:
其中p1, p2……pn为x的所有质因数(只出现一次),x是不为0的整数。
2.数学意义: φ(n) 表示表示 [1,n] 中n 的互质数个数。
3.性质。
1)φ(n)为积性函数,非完全积性。
2)欧拉定理:若 gcd(a,p)=1 ,则 aφ(p)≡1(modp) 。
⟹ 费马小定理:若 gcd(a,p)=1 ,且p是质数,则 ap−1≡1(modp) 。
3) ∑d|nφ(d)=n 神犇的详解:法里级数展开证明
4)线性筛法原理:
φ(n)=∏ipki−1i(pi−1)
//线性筛法求欧拉函数。
memset(phi,0,sizeof(phi));
pt=0,phi[1]=1;
for(int i=2;i<=N;i++)
{
if(!phi[i]){
prime[pt++]=i;
phi[i]=i-1;
}
for(int j=0,u=N/i;jif(i%prime[j]==0)
{
phi[prime[j]*i]=phi[i]*prime[j];
break;
}
else phi[prime[j]*i]=phi[i]*(prime[j]-1);
}
}
莫比乌斯函数
神犇的详解
1.莫比乌斯反演:若 f(d) 是积性函数,则如下 g(n) 也是积性函数。
g(n)=∑d|nf(d)→f(n)=∑d|nμ(d)g(nd)
2.应用:通过 g(n) 的值推出 f(d) 的值。
3.莫比乌斯函数 μ(n) 。
1)函数式: ∑d|nμ(d)=[n=1]
2)求解 μ(m) :由积性函数性质拆分为若干 μ(pk) 分别求解。有如下规律: μ(1)=1,μ(p)=−1,μ(pk)=0(k>=2) 。
//线性筛法求莫比乌斯函数。
memset(miu,0,sizeof(miu));
memset(mark,0,sizeof(mark));
pt=0,miu[1]=1;
for(int i=2;i<=N;i++)
{
if(!mark[i]){
prime[pt++]=i;
miu[i]=-1;
}
for(int j=0,u=N/i;j1;
if(i%prime[j]==0)
{
miu[prime[j]*i]=0;
break;
}
else miu[prime[j]*i]=-miu[i];
}
}
注: marki 表示是否是质数。
乘法逆元
1.定义:如果 ax≡1(modp) ,且 gcd(a,p)=1 ,则称 a 关于模 p 的乘法逆元为 x 。
2.应用。:
目标:求解 ab(modp) 的值。
若 gcd(a,b)=1 ,则无法用直接利用模运算求得。
设 k=f(b) (f(b)表示 b 在模 p 意义下的乘法逆元)
则 ab(modp) 等价于 a×k(modp) 可求解。
3.证明。
若 ax≡1(modp) ,且 gcd(a,p)=1
则 p|(ax−1) 等价于: ax−1=py,y∈Z
写作 ax+py=1 不影响 x 解的结果。
通过exgcd求得x,y的整数解。
//扩展欧几里得算法求逆元。
void exgcd(int a,int b,ll &x,ll &y)
{
if(b==0)x=1,y=0;
else
{
exgcd(b,a%b,x,y);
ll tmp=x;
x=(y+mod)%mod;
y=(tmp-(a/b)*y%mod+mod)%mod;
}
}
若要求 [1,n] 内所有数的乘法逆元?
exgcd的复杂度为 logn ,且有 nlnn≈nlogn 个质数。暴力exgcd就可以得出,但有更简单的方法。
神犇的证明
//线性筛法求逆元。
inv[1]=1;
for(int i=2;i*inv[p%i]%p;
终于都懂了!bravo。