数论入门笔记
目录
一、 数论是什么
数论主要研究整数的性质。需要关注的是一些特殊的数,如质数,素数,最大公约数,最小公倍数等等,以及相应的欧几里得算法,和各种筛法,欧拉函数,积性函数等等等等。。。。。。。
二、数论基础
1. 欧几里德算法(辗转相除法)
可以通过欧几里得算法来算出两个正整数a,b的最大公约数。
复杂度: O ( l o g ( m a x ( a , b ) ) O(log(max(a,b)) O(log(max(a,b))
代码如下(示例):
int gcd(int a, int b){
return b == 0? a : gcd(b,a%b);//b==0 是递归的边界条件
}
下面是该程序的运算过程:
也可以直接调用库函数__gcd(a,b);
2. 有关素数的基础算法
单个整数素性测试
简单素数筛
素数只有:素数它本身和1。判断一个数是否是素数只需检查 2 ~ / ( n ) \sqrt(n) (n)内的整数是否存在有能整除这个数的数就能判断这个数是不是素数。
复杂度: O ( ( n ) ) O(\sqrt(n)) O((n))
代码如下(示例):
bool is_prime()
{
for(int i=2;i*i<=n;i++)
{
if(n%i==0)return false;
}
return n!=1;
}
多个整数素性测试
n内的素数的总数大概是 n / l n ( n ) n/ln(n) n/ln(n)个
埃氏筛法(Eratosthenes筛法)
用于高效去对多个整数进行素数检测(素数的个数<= 1 0 6 10^6 106)
2 ~ n的数写入数组,之后找到最小并且没有被划去的数,之后将在2 ~ n之间这个数的倍数划去,以此枚举n以内的素数。
复杂度: O ( n l o g ( l o g ( n ) ) ) O(nlog(log(n))) O(nlog(log(n)))
代码如下(示例):
#define MAX_N 1000010
int prime[MAX_N];
bool is_prime[MAX_N+1];
int sieve(int n)
{
int p=0;
for(int i=0;i<=n;i++) is_prime[i]=true;
is_prime[0]=is_prime[1]=false;
for(int i=2;i<=n;i++)
{
if(is_prime[i])
{
prime[p++]=i;
for(int j=2*i;j<=n;j+=i)is_prime[j]=false;
}
}
return p;
}
区间筛法
在区间[a,b)上 (a<b<= 1 0 12 10^{12} 1012,b-a<= 1 0 6 10^6 106)
用埃氏筛法算出[2, ( b ) \sqrt(b) (b)]的质数,同时划去[a,b)中这个质数的倍数。
代码如下(示例):
#define MAX_L 1000010
#define MAX_SQRT_B 1000010
typedef long long int ll;
bool is_prime[MAX_L];
bool is_prime_small[MAX_SQRT_B];
void segment_sieve(ll a,ll b){
for(int i=0;(ll)i*i<b;i++)is_prime_small[i]=true;
for(int i=0;i<b-a;i++)is_prime[i]=true;
for(int i=2;(ll)i*i<b;i++)
{
if(is_prime_small[i]){
for(int j=2*i;(ll)j*j<b;j+=i){
is_prime_small[j]=false;}
for(ll j=i*max(2LL,(a+i-1)/i);j<b;j+=i)is_prime[j]=false;
}
}
}
欧拉筛法(线性筛法)
埃氏筛法在筛选时有重复,如6它被素数2和素数3都筛过,像这样的数有很多,而欧拉筛法不会。
int prime[maxn];
int is_prime[maxn];
void Prime(){
mem(is_prime,0);
mem(prime, 0);
for (int i = 2;i <= maxn; i++) {
if (!is_prime[i]) {
prime[++prime[0