前置芝士——线性筛质数
思路
考虑问题 1~x中有多少个质数
1、首先考虑将质数的倍数都标记为合数(即埃筛),时间复杂度 , n上限大约在百万左右。
2、考虑时间复杂度优化:
发现对于合数 6 ,被 质因数 2,3 都筛了一次,造成时间浪费。
所以指定对于每一个合数只被其最小质因数筛掉。
3、实现:对每个数i,如果i是质数则将它加进质数表;把当前数i(不管是质数还是合数)与目前质数表中每个不超过自己最小质因子的质数的乘积变为合数。
原因:i 的最小质因子以后会与更大的合数相乘,枚举质数表中的质数超过i的最小质因子没有必要.
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int x;
int prime[N],tot;//已求得质数表
bool isprime[N];//isprime[i]表示 i 是否为质数
int main(){
cin>>x;
for(int i=2;i<=x;i++){
if(!isprime[i]) {//是质数
prime[++tot]=i;
}
for(int j=1;j<=tot&&i*prime[j]<=x;j++) {
isprime[i*prime[j]]=1;//标记合数
if(i%prime[j]==0) break;//重要优化
}
}
//由于每个数至多被筛一次 ,时间复杂度 O(n)
return 0;
}
欧拉函数
定义
表示 小于等于 n 与 n 互质的数的个数
特别规定
欧拉函数计算式
对于 ,考虑计算1~n中不与 n 互质的个数,即 n 质因数倍数
举个栗子,,2的倍数有 2、4、6、8、10、12;3的倍数有3、6、9、12
发现 6 和 12 重复减了,加上。
自然想到容斥原理
由此易得代码实现
int getphi(int x){
int ans=x;
for(int i=2;i*i<x;i++){
if(x%i==0 ){
ans=ans*(i-1)/i;
while(x%i==0) x/=i;
}
}
if(x>1) ans=ans*(x-1)/x;
return ans;
}
欧拉函数性质
一、欧拉函数是积性函数
积性函数:函数 f(x), 对于互质的数 a,b ,满足
证明 :因为 a,b 互质,所以两者没有相同质因数。由欧拉函数计算式易证。
二、简单性质
(1)若n是质数,φ(n) = n - 1。
(2)若 且p是质数, 则
。
(3)若q是质数,且n % q = 0,则 ;
若q是质数,且n % q ≠ 0,则
上述结论均可由计算式简单推倒得到,在此不多赘述。
三、重要结论
1、
证明先咕着<-^_^->
2、 d=gcd(a,b)
证明:a 的质因数集合为 A,b 的质因数集合为 B,d 的质因数集合 C 为
带入欧拉函数计算式得证
四、其他结论
1、设d(n)表示n的约数的个数,则d(n)是积性函数
证明:令 n = AB,且AB互质。设
d(A) = (x1+1)(x2+1)...(xn+1), d(B) = (y1+1)(y2+1)...(ym+1)。
因为AB互质,所以所有的p和q肯定都是不同的质因子。
d(A)*d(B) = (x1+1)(x2+1)...(xn+1)(y1+1)(y2+1)...(ym+1) = d(n)。
2、设s(n)表示n的所有约数的和,则s(n)是积性函数。
证明:令 n = AB,且AB互质。设
重要特性
积性函数均可由线性筛求值
线性筛求欧拉函数
通过上述性质由线性筛得到
void work(int x){
phi[1]=1;
for(int i=2;i<=x;i++){
if(!isprime[i]) {
prime[++tot]=i;
phi[i]=i-1;//由性质1
}
for(int j=1;j<=tot&&prime[j]*i<=x;j++) {
int fx=prime[j]*i;
isprime[fx]=1;
if(i%prime[j]==0) {
phi[fx]=phi[i]*prime[j];//性质3
break;
}
phi[fx]=phi[i]*(prime[j]-1);//性质3
}
}
}
下期预告:欧拉函数常见题型