数论之素数,包括eratosthenes算法,欧拉函数
2017-01-21 10:29
483 查看
一,素数
素数又称质数,有无限个。除了1和它本身以外不再有其他的除数整除。
算术基本定理:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。
例如:6936=2^3*3*17^2,1200=2^4*3*5^2。
二,质因数的分解
概念:把一个合数用素因数相乘的形式表示出来,叫做质因数分解。(注意:由于任何一个合数n至多会有一个大于根号n的因子)
一般我们用短除法分解素因数,算法步骤如下:
1.先用一个能整除这个合数的素数(通常从最小的开始)去除。
2.得出的商如果是合数,再按照上面的方法继续除下去,直到得出的商是素数为止。
3.然后把各个除数和最后的商按从小到大的顺序写成连乘的形式。
代码如下:cnt=0; //cnt表示素因子的个数
for(int i=2;i*i<=n;i++)//由于任何一个合数至多或有一个大于根号n的因子
{
if(n%i==0)
{
++cnt;
p[cnt]=i;//p数组存的是素因子
num[cnt]=0;//存的是每个素因子的指数
while(n%i==0)
{
++num[cnt];
n/=i;
}//while循环的目的是每次历经一个i,n都会进行更新,或者是有多个i,n也会进行更新
}
}
if(n>1)
{
++cnt;
p[cnt]=n;
num[cnt]=1;
}需要if循环的原因也是因为由于任何一个合数至多或有一个大于根号n的因子(例如n=10)
三,素数的测试
1,一般的思路
bool divisibiity_test(int n)
{
for (int i=2; i<n; i++)
if (n % i == 0)
return false; // 不是质数
return true; // 是质数
}
2,改进的方法
bool divisibiity_test(int n)
{
//一个数至少有一个比sprt(n)小的质因数。
for (int i=2; i<=sqrt(n); i++)
if (n % i == 0)
return false;
return true;
}
时间复杂度:O(sqrtN)
四,Eratosthenes筛法
代码如下:
1,
bool prime[20000000];
void eratosthenes()
{
memset(prime,1,sizeof(prime));
prime[0] = 0; prime[1] = 0; // 0 和 1 不是质数
for (int i=2; i<20000000; i++)
if (prime[i]==1) // 删掉质数i的倍数
for (int j=i+i; j<20000000; j+=i)
prime[j] = 0;
}
2,优化的如下:(优化的原因:删掉质数 i 的倍数时,早已删掉1 倍~ i-1 倍之间的合数了,所以直接从i倍开始删除)。
void eratosthenes(){
memset(prime,1,sizeof(prime));
prime[0] = 0;prime[1] = 0;
for (int i=2; i<20000000; i++)
if (prime[i]==1)
//删掉i的倍数从i倍开始。
for (int j=i*i; j<20000000; j+=i)
prime[j] = 0;
}
五,欧拉函数
1.定理:
对正整数n,欧拉函数φ(phi)指是小于n的所有数中与之互质的个数(包含1)。如φ(8)=4,因为1,3,5,7均和8互质
2.表达形式:n=p1^a1*p2^a2....pk^ak(p1,p2...pk是素数)
3,计算公式:φ(n)=n*(1-1/p1)*(1-1/p2)*......*(1-1/pk)
例如:φ(8)=4有1,3,5,7,8=2^3, φ(8)=8*(1-1/2)=4.
φ(10)=4有1,3,7,9 ,10=2*5,φ(10)=10*(1-1/2)*(1-1/5)=4.
4,性质:
a)当p为质数时, φ(p) = p – 1。
证明:因为小于本身的数都与该数互质,但是注意φ(1)=1.
b)对于互质的正整数a和n,有a^φ(n) ≡ 1 (mod n) (mod n的意思是两边同时%n).
c)费马小定理:若正整数a 与素数p 互质,则有a^(p - 1)≡1 mod p。
证明:由于性质a可知当p为质数,φ(p) = p -1,代入性质b即可证明。
d)当n为奇数时φ(2n)=φ(n).
e)当n和m互质时,φ(n*m)=φ(n)*φ(m).
f)若n=p^k(p为质数),φ(n)=p^k-p^(k-1).
证明:因为除了p的倍数外,其他数都跟n互质。
朴素算法实现:
1.根据公式1:n=p1^k1*p2^k2*…*pr^kr和公式2:φ(n)=n* (1-1/p1) *…* (1-1/pr)。
2.可将公式2可拆成n* (1-1/p1)=n-n/p1计算。
代码实现:
int euler(int n)
{
int i,ans=n;
for(i=2; i*i<=n; i++)
if(n%i==0)
{
ans=ans-ans/i;
do
n/=i;//把该素因子全部约掉
while(n%i==0);
}
if(n>1)
ans=ans-ans/n;
return ans;
}
例题:
Total Submission(s):
319 Accepted Submission(s):
44
(已经AC过的代码)
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int IsPrimeNumber(int n)
{
if (n==2)
{
return true;
}
if (n%2==0)
{
return false;
}
int sqrtn=(int)sqrt((double)n);
bool flag=true;
for (int i=3; i<=sqrtn; i+=2)
{
if (n%i==0)
{
flag=false;
}
}
return flag;
}
int main()
{
int m,n,x;
while(scanf("%d",&m)!=EOF)
{
int sum=0;
for(int k=0; k<m; k++)
{
scanf("%d",&n);
x=IsPrimeNumber(n);
if(x)
sum++;
}
cout<<sum<<'\n';
}
return 0;
}
素数又称质数,有无限个。除了1和它本身以外不再有其他的除数整除。
算术基本定理:每个大于1的自然数均可写为质数的积,而且这些素因子按大小排列之后,写法仅有一种方式。
例如:6936=2^3*3*17^2,1200=2^4*3*5^2。
二,质因数的分解
概念:把一个合数用素因数相乘的形式表示出来,叫做质因数分解。(注意:由于任何一个合数n至多会有一个大于根号n的因子)
一般我们用短除法分解素因数,算法步骤如下:
1.先用一个能整除这个合数的素数(通常从最小的开始)去除。
2.得出的商如果是合数,再按照上面的方法继续除下去,直到得出的商是素数为止。
3.然后把各个除数和最后的商按从小到大的顺序写成连乘的形式。
代码如下:cnt=0; //cnt表示素因子的个数
for(int i=2;i*i<=n;i++)//由于任何一个合数至多或有一个大于根号n的因子
{
if(n%i==0)
{
++cnt;
p[cnt]=i;//p数组存的是素因子
num[cnt]=0;//存的是每个素因子的指数
while(n%i==0)
{
++num[cnt];
n/=i;
}//while循环的目的是每次历经一个i,n都会进行更新,或者是有多个i,n也会进行更新
}
}
if(n>1)
{
++cnt;
p[cnt]=n;
num[cnt]=1;
}需要if循环的原因也是因为由于任何一个合数至多或有一个大于根号n的因子(例如n=10)
三,素数的测试
1,一般的思路
bool divisibiity_test(int n)
{
for (int i=2; i<n; i++)
if (n % i == 0)
return false; // 不是质数
return true; // 是质数
}
2,改进的方法
bool divisibiity_test(int n)
{
//一个数至少有一个比sprt(n)小的质因数。
for (int i=2; i<=sqrt(n); i++)
if (n % i == 0)
return false;
return true;
}
时间复杂度:O(sqrtN)
四,Eratosthenes筛法
代码如下:
1,
bool prime[20000000];
void eratosthenes()
{
memset(prime,1,sizeof(prime));
prime[0] = 0; prime[1] = 0; // 0 和 1 不是质数
for (int i=2; i<20000000; i++)
if (prime[i]==1) // 删掉质数i的倍数
for (int j=i+i; j<20000000; j+=i)
prime[j] = 0;
}
2,优化的如下:(优化的原因:删掉质数 i 的倍数时,早已删掉1 倍~ i-1 倍之间的合数了,所以直接从i倍开始删除)。
void eratosthenes(){
memset(prime,1,sizeof(prime));
prime[0] = 0;prime[1] = 0;
for (int i=2; i<20000000; i++)
if (prime[i]==1)
//删掉i的倍数从i倍开始。
for (int j=i*i; j<20000000; j+=i)
prime[j] = 0;
}
五,欧拉函数
1.定理:
对正整数n,欧拉函数φ(phi)指是小于n的所有数中与之互质的个数(包含1)。如φ(8)=4,因为1,3,5,7均和8互质
2.表达形式:n=p1^a1*p2^a2....pk^ak(p1,p2...pk是素数)
3,计算公式:φ(n)=n*(1-1/p1)*(1-1/p2)*......*(1-1/pk)
例如:φ(8)=4有1,3,5,7,8=2^3, φ(8)=8*(1-1/2)=4.
φ(10)=4有1,3,7,9 ,10=2*5,φ(10)=10*(1-1/2)*(1-1/5)=4.
4,性质:
a)当p为质数时, φ(p) = p – 1。
证明:因为小于本身的数都与该数互质,但是注意φ(1)=1.
b)对于互质的正整数a和n,有a^φ(n) ≡ 1 (mod n) (mod n的意思是两边同时%n).
c)费马小定理:若正整数a 与素数p 互质,则有a^(p - 1)≡1 mod p。
证明:由于性质a可知当p为质数,φ(p) = p -1,代入性质b即可证明。
d)当n为奇数时φ(2n)=φ(n).
e)当n和m互质时,φ(n*m)=φ(n)*φ(m).
f)若n=p^k(p为质数),φ(n)=p^k-p^(k-1).
证明:因为除了p的倍数外,其他数都跟n互质。
朴素算法实现:
1.根据公式1:n=p1^k1*p2^k2*…*pr^kr和公式2:φ(n)=n* (1-1/p1) *…* (1-1/pr)。
2.可将公式2可拆成n* (1-1/p1)=n-n/p1计算。
代码实现:
int euler(int n)
{
int i,ans=n;
for(i=2; i*i<=n; i++)
if(n%i==0)
{
ans=ans-ans/i;
do
n/=i;//把该素因子全部约掉
while(n%i==0);
}
if(n>1)
ans=ans-ans/n;
return ans;
}
例题:
1286.有多少素数
Time Limit: 1000 MS Memory Limit: 32768 KBTotal Submission(s):
319 Accepted Submission(s):
44
Description
给你很多的正整数,只是为了找出有多少素数。Input
有很多的测试用例,每个测试用例第一行是正整数N,表示要从N个整数中找。每个整数不超过2147483647,其中每个不小于2。Output
对于每种情况输出素数的个数。Sample Input
3 2 3 4
Sample Output
2
(已经AC过的代码)
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
int IsPrimeNumber(int n)
{
if (n==2)
{
return true;
}
if (n%2==0)
{
return false;
}
int sqrtn=(int)sqrt((double)n);
bool flag=true;
for (int i=3; i<=sqrtn; i+=2)
{
if (n%i==0)
{
flag=false;
}
}
return flag;
}
int main()
{
int m,n,x;
while(scanf("%d",&m)!=EOF)
{
int sum=0;
for(int k=0; k<m; k++)
{
scanf("%d",&n);
x=IsPrimeNumber(n);
if(x)
sum++;
}
cout<<sum<<'\n';
}
return 0;
}
相关文章推荐
- algorithm@ Sieve of Eratosthenes (素数筛选算法) & Related Problem (Return two prime numbers )
- 用Eratosthenes筛子算法,求解从2到n之间的素数
- 查找素数的Eratosthenes(筛子)算法终止条件解释
- Eratosthenes 筛选素数
- Eratosthenes筛法求1-100之间的素数
- 找质数算法(Sieve of Eratosthenes筛法)
- 素数表(Eratosthenes)
- 学习笔记——求解素数问题之Eratosthenes(埃拉托色尼)筛选法
- sieve of Eratosthenes——一种寻找素数的方法
- 素数表(Eratosthenes)
- 找质数算法(Sieve of Eratosthenes筛法)
- 找质数算法(Sieve of Eratosthenes筛法)
- The Sieve of Eratosthenes (素数筛选法)
- 著名的Eratosthenes求素数方法(程序员的数学思维修炼)
- Eratosthenes 法找素数 (含代码)
- Sieve Of Eratosthenes求素数(埃拉托斯特尼筛法)
- Eratosthenes筛法,求素数
- 素数筛总结篇___Eratosthenes筛法和欧拉筛法(*【模板】使用 )
- 素数筛——Eratosthenes 素数筛、Euler 素数筛
- Sieve of Eratosthenes(埃拉托斯特尼素数筛选法)--java实现