数论总结

目录

1.质数

1.1质数的判定

1.1.1试除法

1.2 质数的筛选

1.2.1埃拉托斯尼筛法

1.2.2线性筛法

1.3 质因数分解

2.约数

2.1求N的正约数集合

2.1.1 试除法

2.2.2 倍数法

3.最大公约数和最小公倍数

3.1 九章算术--更相减损术

3.2欧几里得算法

4.互质与欧拉函数

4.1互质

4.2欧拉函数

4.2.1证明

4.2.2性质

 4.2.3线性筛法求欧拉函数


1.质数

定义:质数又称素数,指在大于1的自然数中,除了1和该数自身外,无法被其他自然数整除的数(也可定义为只有1与该数本身两个正因数的数)。大于1的自然数若不是素数,则称之为合数(也称为合成数)。

算术基本定理,又称为正整数的唯一分解定理,即:每个大于1的自然数,要么本身就是质数,要么可以写为2个或以上的质数的积,而且这些质因子按大小排列之后,写法仅有一种方式。(即合数可以分解为两个或两个以上质数的乘积,此处和哥德巴赫猜想有点类似:任一大于2的偶数,都可表示成两个素数之和。)

算术基本定理的内容由两部分构成:

•      分解的存在性:

•      分解的唯一性,即若不考虑排列的顺序,正整数分解为素数乘积的方式是唯一的。

 

对于一个足够大的整数N,不超过N的质数大约由N/lnN个,即每lnN个数中大约有1个质数。


先验知识就介绍到这里,接下来介绍质数的判定和筛法

1.1质数的判定

1.1.1试除法

试除法就是扫描2~\sqrt{N}之间的所有整数,依次检查它们是否能整除N,若都不能整除,则N是质数,否则N是合数。试除法的时间复杂度是O(\sqrt{N})。需要特判0和1这两个整数,它们既不是质数,也不是合数。

模板如下:

bool is_prime(int n)
{
    if(n<2) return false;
    for(int i = 2; i <= sqrt(n); i++)
        if( n % i == 0) return false;
    return true;
}

 

1.2 质数的筛选

给定一个整数N,求出1~N之间的所有质数,称之为质数的筛选问题。

1.2.1埃拉托斯尼筛法

(第一次看见这个埃拉托斯尼这个名字是在初一的一本课外读物上,书上介绍他是古希腊的全才,他是第一个测量地球周长的人,那时觉得2200年前的人就能测出地球的周长真的是非常了不起,当然现在也还是觉得非常了不起。)

埃拉托斯尼筛法基于这样的想法:任意整数x的倍数2x,3x,...都不是质数。

埃拉托斯特尼筛法
维基百科-埃拉托斯尼筛法

 

另外,2和3都会把6标记为合数,事实上,小于x^{2}的数在扫描更小的数时就已经被标记过了(因为任意一个合数N,其必存在一个质因子小于\sqrt{N})。因此,对于每个数x,我们只需从x^{2}开始,把x^{2},(x+1)*x,...,\left \lfloor N/x \right \rfloor*x标记N为合数即可。

时间复杂度约为O(NloglogN)

模板如下:

void primes(int n)
{
    memset(v,0,sizeof(v)); //合数标记
    for(int i = 2; i <= n; i++)
    {
        if(v[i]) continue;
        cout << i << endl; //i是质数
        for(int j = i; j <= n/i; j++) v[i*j] = 1;
    }
}

1.2.2线性筛法

即使在优化后(从x^{2}开始),埃拉托斯尼筛法仍然会重复标记合数。例如12会被2和3标记。其根本原因是我们没有确定出唯一的产生12的方式。

线性筛法通过“从小到大累积质因子”的方式标记每个合数。

设数组v来记录每个数的最小质因子,按照以下步骤来维护v:

1.依次考虑2~N之间的每一个数i

2.若v[i] = i,说明i是质数,添加到质数表中

3.扫描不大于v[i]的每个质数p,令v[i*p] = p. 也就是在i的基础上累积一个质因子p。因为p<=v[i],所有p是合数i*p的最小质因子。

每个合数i*p只会被它的最小质因子p筛选一次,时间复杂度为O(n).

模板:

const int MAX_N = 200010;

int v[MAX_N], prime[MAX_N];

void primes(int n)
{
    memset(v,0,sizeof(v)); //存放每个数的最小质因子
    int m = 0; //质数数量
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0) { v[i] = i; prime[++m] = i; }
        //给当前的数i乘上一个质因子
        for(int j=1;j<=m;j++)
        {
            //i有比prime[j]更小的质因子,或者超出n的范围,停止循环
            if(prime[i]>v[i] || prime[j]>n/i) break;
            v[i*prime[j]] = prime[j];
        }
    }
    for(int i=1;i<=m;i++) cout<<prime[i]<<endl;
}

1.3 质因数分解

质因数分解就是前面提到的算术基本定理。

模板:

const int MAX_N = 200010;

int prime[MAX_N],c[MAX_N];

void divide(int n)
{
    int m = 0;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0) //i为质数
        {
            prime[++m] = i, c[m] = 0;
            while(n%i==0) n /= i, c[m]++;  //除掉所有的i并计数
        }
    }
    //n为质数
    if(n>1) prime[++m] = n, c[m] = 1;
    for(int i=1;i<=m;i++) cout<<prime[i]<<'^'<<c[i]<<endl;
}

 

2.约数

若整数n除以整数d的余数为0,即d能整除n,则称d是n的约数,n是d的倍数。

2.1求N的正约数集合

2.1.1 试除法

扫描1~\sqrt{N}},尝试d能否整除N,若能整除,则N/d也是N的约数。

int factor[1600],m=0;

void fac(int n)
{
    for(int i=1;i*i<=n;i++)
    {
        if(n%i==0)
        {
            factor[++m]=i;
            if(i!=n/i) factor[++m] = n/i;
        }
    }
    for(int i=1;i<=m;i++) cout<<factor[i]<<endl;
}

推论:一个整数N的约数个数上界为2\sqrt{N}}

2.2.2 倍数法

求出1~N的每个数的正约数集合

const int M = 500010;
vector<int> factor[M];

void div(int n)
{
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n/i;j++)
            factor[i*j].push_back(i);
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<factor[i].size();j++)
            cout<<factor[i][j]<<' ';
        cout<<endl;
    }
}

 

3.最大公约数和最小公倍数

定理:最大公约数gcd(a,b)和最小公倍数关系:gcd(a,b)*lcm(a,b) = a*b

3.1 九章算术--更相减损术

\forall a,b\in \mathbb{N},a\geqslant b, 有  gcd(a,b)=gcd(b,a-b)=gcd(a,a-b)

对于a,b的任意公约数d,有d|a,d|b,所以d|(a-b),即d也是b,a-b的公约数,反之亦成立。

\forall a,b\in \mathbb{N},gcd(2a,2b)=2gcd(a,b)

3.2欧几里得算法

\forall a,b\in \mathbb{N},b\neq 0,gcd(a,b)=gcd(b,a\,mod\, b)

模板:

int gcd(int a, int b){
    return b ? gcd(b, a % b) : a;
}

由于高精度除法(取模)不容易实现,需要做高精度运算时,可考虑用更相减损术代替欧几里得算法。

 

4.互质与欧拉函数

4.1互质

定义:若a,b的最大公约数为1,则称a,b互质

4.2欧拉函数

1~N中与N互质的数的个数被称为欧拉函数,记为\varphi (N)

4.2.1证明

设p是N的质因子,1~N中p的倍数有p,2p,3p,...,(N/p)*p,共N/p个。

同理,若q也是N的质因子,则1~N中q的倍数有N/q个。如果把这N/p+N/q个数去掉,那么p*q的倍数被排除了两次,需要加回来一次。因此,1~N中不与N含有共同质因子p或q的数的个数为:

N-\frac{N}{q}-\frac{N}{p}+\frac{N}{pq} = N*(1-\frac{1}{q}-\frac{1}{p}+\frac{1}{pq})=N(1-\frac{1}{q})(1-\frac{1}{p})

类似地,可以在N的全部质因子上使用该方法,即可得到欧拉函数。

 

根据欧拉函数的计算式,我们只需分解质因数,即可求出欧拉函数

int phi(int n)
{
    int ans = n;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0)
        {
            ans = ans/i*(i-1);
            while(n%i==0) n/=i;
        }
    }
    if(n>1) ans = ans/n*(n-1);
    return ans;
}

4.2.2性质

1.任意n>1, 1~n 中与 n 互质的数的和为 n*\varphi (n)/2.

证明:因为gcd(n,x)=gcd(n,n-x),所以与n不互质的数x,n-x成对出现,平均值为n/2,因此,与n互质的数的平均值也是n/2.

 

2.若a,b互质,则\varphi(ab)=\varphi(a)\varphi(b)

积性函数:如果a,b互质,f(ab)=f(a)*f(b),那么称 f 为积性函数。

 

3.若f是积性函数,且在算术基本定理中n = \prod_{i=1}^{m}p_{i}^{c_{i}},则f(n) = \prod_{i=1}^{m}f(p_{i}^{c_{i}})

4.设p为质数,若p|n且p^{2}}|n ,则\varphi (n)=\varphi (n/p)*p

证明:若p|n且p^{2}}|n,则n,n/p包含相同的质因子,只是p的指数不同。直接把\varphi (n)\varphi (n/p)按照欧拉公式的计算公式写出,二者相除商为p,所以性质4成立。

5.设p为质数,若p|n但p^{2}}不是n的约数,则\varphi (n)=\varphi (n/p)*(p-1)

证明:推出p,n/p互质,有欧拉函数是积性函数得\varphi (n)=\varphi (n/p)*\varphi (p),而\varphi (p)=p-1(p为质数),所以性质5成立。

6.  \sum _{d|n}\varphi (d)=n

 

 4.2.3线性筛法求欧拉函数

利用性质4和性质5

const int MAX_N = 200010;

int v[MAX_N], prime[MAX_N],phi[MAX_N];

void euler(int n)
{
    memset(v,0,sizeof(v)); //存放每个数的最小质因子
    int m = 0; //质数数量
    for(int i=2;i<=n;i++)
    {
        if(v[i]==0) { v[i] = i; prime[++m] = i; phi[i] = i-1; }
        //给当前的数i乘上一个质因子
        for(int j=1;j<=m;j++)
        {
            //i有比prime[j]更小的质因子,或者超出n的范围,停止循环
            if(prime[i]>v[i] || prime[j]>n/i) break;
            v[i*prime[j]] = prime[j];
            phi[i*prime[j]] = phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
        }
    }
}

4.12日更新

5.同余

定义:若整数a和整数b除以正整数

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值