质数
质数的定义
质数又称作素数.
质数是除了1和本身没有其他因数的数.
与之相反的是合数.
1不属于质数或合数.
质数的判断
假设我们要判断n是不是质数.
从2枚举n−1,若能整除n,n就不是质数.
时间复杂度O(n).
但因数是成对的(除了n)
令n=c1c2,假设c1≤c2
则c1≤n,c2≥n
所以只需枚举到n.
bool isprime(long long x) {
for(int i=2; i<=sqrt(x); i++) {
if(x%i==0) return false;
}
return true;
}
时间复杂度O(n).
质数筛法
现在我们要求1到n中全部质数.
暴力
最简单的办法就是判断每个数是否为质数.
时间复杂度O(nn).
埃氏筛法
从1到n,若这个数没有被标记,即为质数.
只要发现了一个质数t,就把从1到n中全部t的倍数标记.
时间复杂度O(nlogn)
欧拉线性筛法
对于每个i(1<i<n),筛去所有小于i的质数与i的乘积.
不难发现,有些合数被重复筛去.
设所有小于i的质数分别为p1,p2,...,pj.
当i%pk=0时,停止筛i的倍数,即可避免重复.
因为当l>k时,所有i∗pl都会被比i大的数与pk的乘积筛去.
for(int i=2;i<=n;i++){
if(!vis[i]) {
cnt++;
pri[cnt]=i;
}
for(int j=1;i*pri[j]<=n;j++){
vis[i*pri[j]]=true;
if(i%pri[j]==0) break;
}
}
时间复杂度O(n)
质因数分解
一个数的质因数必定小于等于n.
只需把i从2枚举到n,从n中去掉所有i并做记录,就能求出n的质因数.
for(int i=2;i<=sqrt(n);i++) {
while(n%i==0) {
n/=i;
cnt[i]++;
}
}
时间复杂度O(n)
欧拉函数
欧拉函数是从1到n−1的数中与n互质的数的个数.
φ(1)=φ(2)=1.
性质
- 对于质数n,φ(n)=n−1.
- 对于质数p,φ(pk)=(p−1)∗pk−1.
- 对于互质的n,m,φ(n)∗φ(m)=φ(n∗m).
- 对于奇数n,φ(2∗n)=φ(n).
- 对于n(n>1),∑k=1nk(gcd(n,k)=1)=φ(n)∗n/2.
- 若k%p=0,φ(k∗p)=φ(k)∗p.
- 若k%p!=0,φ(k∗p)=φ(k)∗(p−1).
- 对于互质的a,m,aφ(p)≡1(modp).
- ∑k∣nnφ(k)=n
- φ(n)=∑k∣nnφ(k)∗kn.
计算公式及证明
设n的质因数分解为p1c1∗p2c2∗…∗pici.
则φ(n)=n∗p1p1−1∗p2p2−1∗…∗pipi−1
证明:设p,q是n的质因子.
则1-n中,p的倍数有pn个,q的倍数有qn个,p∗q的倍数有p+qn个.
所以1到n−1中与p,q互质的数的个数为
KaTeX parse error: No such environment: align* at position 7: \begin{̲a̲l̲i̲g̲n̲*̲}̲ n-\frac{n}{p}-…
其他质因子同理.
算法实现
对于求单个欧拉函数,分解质因数即可.
for(long long i=2;i<=sqrt(num);i++) {
bool div=false;
while(num%i==0) {
div=true;
num/=i;
}
if(div) ans=ans*(i-1)/i;
}
if(num>1) ans=ans*(num-1)/num;
时间复杂度与质因数分解一样.
但如果要求从1到n的数的欧拉函数,就可以通过打表法来求解.
for(int i=2;i<=MAXN;i++) {
if(!phi[i]) {
for(int j=i;j<=MAXN;j+=i) {
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
或是在欧拉筛时同时求出欧拉函数.
for(int i=2;i<=n;i++){
if(!vis[i]) {
cnt++;
pri[cnt]=i;
phi[cnt]=i-1;
}
for(int j=1;i*pri[j]<=n;j++){
vis[i*pri[j]]=true;
if(i%pri[j]==0) {
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
}
}
gzezFISHER
发布了1 篇原创文章 · 获赞 0 · 访问量 6
私信
关注