线性筛
线性筛
线性筛真是一种很神奇的科技.有的函数单个求非常慢,但是因为有一些优秀的性质,所以可以线性筛,从而将均摊复杂度降为$O(1)$.
积性函数都可以线性筛(据说).要线筛应该满足这样的性质:
可以快速的求出$f(1),f(p),f(p^k)$.这样一来就可以方便的求出其他所有函数值了.不过实际应用中主要关注的是两个有倍数关系的函数值之间的关系.
从刚刚的性质可以看出,所有的线性筛都必须以线性筛素数为基础(设想求素数需要$NlogN$,那么后面为了降低复杂度的所有操作就都没用了)
现在从线性筛素数开始学习线性筛.
首先根据一般性的做法,写出式子:
$f(n)= \left\{\begin{matrix}0,n=1 \\ 1,n=p \\0,n=p^k \end{matrix}\right.$
然后就没了啊...
下面是代码:
1 for (R i=2;i<=n;++i) 2 { 3 if(!vis[i]) pri[++h]=i; 4 for (R j=1;j<=h&&i*pri[j]<=n;++j) 5 { 6 vis[ i*pri[j] ]=1; 7 if(i%pri[j]==0) break; 8 } 9 }
这里比较有趣的是第7行,它保证了时间复杂度.如果每个数只被自己最小的那个质因子筛掉就可以满足线性复杂度.对于第7行,如果条件为真,说明$pri(j)$是$i$的最小质因子,就不应该再用$i$去筛其它的数了,因为这些数的最小质因子都应该是$pri(j)$.
莫比乌斯函数:
$\mu(n)= \left\{\begin{matrix}1,n=1 \\ -1,n=p \\0,n=p^k \end{matrix}\right.$
1 for (R i=2;i<=maxn;++i) 2 { 3 if(!vis[i]) 4 pri[++h]=i,mu[i]=-1; 5 for (R j=1;j<=h&&i*pri[j]<=maxn;++j) 6 { 7 vis[ i*pri[j] ]=1; 8 if(i%pri[j]==0) break; 9 mu[ i*pri[j] ]=-mu[i]; 10 } 11 }
欧拉函数:
1 for(R i=2;i<n;++i) 2 { 3 if(f[i]) 4 { 5 pri[++h]=i; 6 phi[i]=i-1; 7 } 8 for(R j=1;j<=h&&i*pri[j]<n;++j) 9 { 10 if(i%pri[j]==0) 11 { 12 phi[i*pri[j]]=phi[i]*pri[j]; 13 break; 14 } 15 phi[i*pri[j]]=phi[i]*(pri[j]-1); 16 } 17 }
约数个数:
这里先说一个利用唯一分解定理求单个数字的约数个数的方法.
$n=\prod p_i^{a_i},d(n)=\prod(1+a_i)$
其实这里已经用到了积性函数的思想.
线性筛:$d(n)= \left\{\begin{matrix}1,n=1 \\ 2,n=p \\k+1,n=p^k \end{matrix}\right.$
实际运用中还要记录每个数最小质因子的出现次数。
1 d[1]=1; 2 for (R i=2;i<=n;++i) 3 { 4 if(!vis[i]) pri[++h]=i,d[i]=2,m[i]=1; 5 for (R j=1;j<=h&&i*pri[j]<=n;++j) 6 { 7 vis[ i*pri[j] ]=1; 8 if(i%pri[j]==0) 9 { 10 m[ i*pri[j] ]=m[i]+1; 11 d[ i*pri[j] ]=d[i]/(m[i]+1)*(m[i]+2); 12 break; 13 } 14 d[ i*pri[j] ]=d[i]*2; 15 m[ i*pri[j] ]=1; 16 } 17 }
约数和:
$\sigma(n)= \left\{\begin{matrix}1,n=1 \\ p+1,n=p \\ \sum_{i=0}^k p^i,n=p^k \end{matrix}\right.$
那么对于每一个数需要保存它的最小质因子的那一项的等比数列,一种比较好想的做法是同时保留$p^k$,转移时把这一项乘上一个$p$再加进等比数列,下面是代码。
1 d[1]=1; 2 for (R i=2;i<=n;++i) 3 { 4 if(!vis[i]) pri[++h]=i,m[i]=i,t[i]=1,d[i]=i+1,p[i]=i,s[i]=i+1; 5 for (R j=1;j<=h&&i*pri[j]<=n;++j) 6 { 7 vis[ i*pri[j] ]=true; 8 if(i%pri[j]==0) 9 { 10 m[ i*pri[j] ]=pri[j]; 11 t[ i*pri[j] ]=t[i]+1; 12 p[ i*pri[j] ]=p[i]*pri[j]; 13 s[ i*pri[j] ]=s[i]+p[ i*pri[j] ]; 14 d[ i*pri[j] ]=d[i]/s[i]*s[ i*pri[j] ]; 15 break; 16 } 17 d[ i*pri[j] ]=d[i]*(pri[j]+1); 18 t[ i*pri[j] ]=1; 19 s[ i*pri[j] ]=1+pri[j]; 20 p[ i*pri[j] ]=pri[j]; 21 m[ i*pri[j] ]=pri[j]; 22 } 23 }
但是这样会使代码变得很长,而且常数比较大,考虑等比数列后再填一项还可以怎么转移,平移一下!$(1+p+p^2+...+p^k) \times p+1=1+p+p^2+...+p^{k+1}$
1 d[1]=1; 2 for (R i=2;i<=n;++i) 3 { 4 if(!vis[i]) pri[++h]=i,d[i]=i+1,s[i]=i+1; 5 for (R j=1;j<=h&&i*pri[j]<=n;++j) 6 { 7 vis[ i*pri[j] ]=true; 8 if(i%pri[j]==0) 9 { 10 s[ i*pri[j] ]=s[i]*pri[j]+1; 11 d[ i*pri[j] ]=d[i]/s[i]*s[ i*pri[j] ]; 12 break; 13 } 14 d[ i*pri[j] ]=d[i]*(pri[j]+1); 15 s[ i*pri[j] ]=1+pri[j]; 16 } 17 }
那么来看一道例题:
$f(n)=\sum_{d|n}d^k\mu(\frac{n}{d})$
想一下-------
$f(n)= \left\{\begin{matrix}1,n=1 \\ p^k-1,n=p \\p^k\times f(p^{k-1}),n=p^k \end{matrix}\right.$
1 for (R i=2;i<=maxn;++i) 2 { 3 if(!vis[i]) mu[i]=-1,pri[++h]=i,g[i]=(f[i]-1+mod)%mod,ls[i]=i; 4 for (R j=1;j<=h&&i*pri[j]<=maxn;++j) 5 { 6 vis[ i*pri[j] ]=1; 7 ls[ i*pri[j] ]=pri[j]; 8 if(i%pri[j]==0) 9 { 10 g[ i*pri[j] ]=g[i]*f[ pri[j] ]%mod; 11 break; 12 } 13 mu[ i*pri[j] ]=-mu[i]; 14 g[ i*pri[j] ]=(g[i]*g[ pri[j] ])%mod; 15 } 16 }
以后看到什么有趣的函数筛再补充吧.