线性筛法&积性函数
线性筛主要考筛选质数和求积性函数。
埃氏筛法
这个不是线性筛,时间复杂度是 \(O(n \log \log{n})\) 。也可以以较高的效率筛选出质数。埃氏筛的思路简单。如果当前是质数,就枚举它的倍数,并都标记为合数。小优化:只要筛到 \(\sqrt{n}\) 就好了。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e8+5;
int n,q;
bool vis[N];
int p[5800005],cnt;
void prime(){
for(int i=2;i<=n;i++){
if(vis[i])continue;
p[++cnt]=i;
if(1LL*i*i>n)continue;
for(int j=i*i;j<=n;j+=i)vis[j]=true;
}
}
int main(){
scanf("%d%d",&n,&q);
prime();
while(q--){
int x;
scanf("%d",&x);
printf("%d\n",p[x]);
}
return 0;
}
欧拉筛法
这是常用的线性筛,时间复杂度 \(O(n)\) 。欧拉筛的核心是每个数只被它最小的质因子筛去,保证每个数只被筛一次。筛选的时候如何保证是最小的质因子?枚举质因子 \(j\) ,是从小到大的。当前的数 \(i\) 是倍数,所以筛选掉 \(p_j \times i\) 。如果出现 \(i \equiv 0 \pmod {p_j}\) ,就说明倍数 \(i\) 中已经出现因子 \(p_j\) 了,此时 \(p_j\) 仍然是最小质因子,但再往下枚举就不是了。
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e8+5;
int n,q;
bool vis[N];
int p[5800005],cnt;
void prime(){
vis[1]=true;
for(int i=2;i<=n;i++){
if(vis[i]==false)p[++cnt]=i;
for(int j=1;1LL*p[j]*i<=n&&j<=cnt;j++){
vis[p[j]*i]=true;
if(i%p[j]==0)break;
}
}
}
int main(){
scanf("%d%d",&n,&q);
prime();
while(q--){
int x;
scanf("%d",&x);
printf("%d\n",p[x]);
}
return 0;
}
积性函数
当 \(x \perp y\) 时,存在 \(f(xy)=f(x)f(y)\) ,那么 \(f\) 是积性函数。
如果 \(f(xy)=f(x)f(y)\) ,那么 \(f\) 是完全积性函数。
性质:
-
如果 \(f, \ g\) 都是积性函数, 那么 \(f \cdot g\) 也是积性函数
-
如果 \(f, \ g\) 都是积性函数, 那么他们的狄利克雷卷积 \(\displaystyle h(x)=\sum_{d|x}f(d) \cdot g(\frac{x}{d})\) 也是积性函数
常见的积性函数有:
- \(\varphi (n)\) :欧拉函数
- \(\mu (n)\) :莫比乌斯函数
- \(d(n)\) :\(n\) 的约数个数
- \(\sigma(n)\) :\(n\) 的约数之和
- \(f(x)=x^k , \ (k \in \mathbb{R})\) :幂函数
欧拉函数
小于等于 \(n\) 的正整数中与 \(n\) 互质的数量,记作 \(\varphi (n)\) 。
性质:
- \(\varphi(1)=1\)
- 如果 \(n\) 是质数,\(\varphi(n)=n-1\) 。如果 \(n\) 是合数,\(\varphi(n)<n-1\) 。
- \(\varphi(p^k)=p^k-p^{k-1}\) 。证明:小于等于 \(p^k\) 的正整数一共有 \(p^k\) 个。假设固定一个质因子 \(p\) ,枚举倍数 \(i\) ,此时 \(p \times i\) 一定不与 \(p^k\) 互质,共 \(p^{k-1}\) 个。
- 欧拉定理:如果 \(a \perp m\) ,则 \(a^{\varphi(m)} \equiv 1 \pmod{m}\) 。所以费马小定理是欧拉定理的特例。
- \(\displaystyle n=\sum_{d|n}{\varphi(d)}\)
(未完成)

浙公网安备 33010602011771号