数论基础

数学

//本篇为学习记录,会一直更新

常见符号:

  1. 整除符号:(x) (|) (y),​ (x)整除(y)

  2. 取模符号:(x) (mod) (y)(x)除以(y) 的余数

  3. 互质符号: (x) (ot) (y)(x)除以(y) 的余数

  4. 最大公约数:(gcd(x,y)),简写为((x,y))

  5. 最小公倍数:(lcm(x,y)),简写为(left[x,y ight])

  6. 求和符号:(sum)

  7. 求积符号:(prod)

数论基础:

1)素数判定:

如果存在一个整数(k),使得(a=kd),则称(d)整除(a),记作(d) (|) (a),即(a)(d)的倍数,(k)叫做他们的约数

那么如果除了(1)和它本身外,不存在任意的(k),使得(d) (|) (a),那么就叫这个(a)为素数(质数)

(1)既不是质数也不是合数

素数的判定方法:

1. (O(n))

bool is_prime(int n)
{
    int flag=0;
    for(int i=2;i<n;i++)
    {
        if(n%i==0) 
        {
            flag=1;
            break;
        }
    }
    if(flag) return 0;
    else return 1;
}

2.(O(sqrt(n)))

因为质数的分布是以(sqrt(n))为界限对称分布的,所以只去遍历((2-sqrt(n)))就可以得到所有的约数

bool is_prime(int n)
{
    int flag=0;
    for(int i=2;i*i<=n;i++)
    {
        if(n%i==0) 
        {
            flag=1;
            break;
        }
    }
    if(flag) return 0;
    else return 1;
}

2) 素数筛

假设(n=1000000),如果我们想要知道(1-n)之间有多少个素数,分别是多少,很明显,直接对每一个数去判断他是否是质数的时间复杂度是(o(n*sqrt(n)))

对于(1000000)的数据规模预处理也是有可能 tle 的,所以我们并不考虑这样的预处理方式

对于(iin[1,n])的每一个数(i),如果(i)是一个合数的话,只让他被最小的质因子筛一次,时间复杂度(O(n))

每次我们遍历([2,n]) 的每一个数,如果遍历到了(i) 那就证明他已经被比他小的数筛过了,如果没有被标记,那就证明他是一个质数,然后我们遍历已经被筛过的质数,把他的倍数全都标记上,如果(i\%prime[j]==0),那(i=prime[j]*x) ,下一次循环的(i*prime[j+1]=prime[j]*x*prime[j+1]) ,但(prime[j])一定比(prime[j+1])小,所以就不用再筛下去了,(i*prime[j+1])一定被筛过了

int vis[maxn],prime[maxn],cnt=0;
void init(int n)
{
    vis[0]=1;
    vis[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]) prime[cnt++]=i;
        for(int j=0;j<cnt&&i*prime[j]<=n;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
// 质数的vis=0,prime下标从0开始

3) 同余式

如果两个数(a,b)在模(n)意义下的答案相等,那么我们就说(a)(b)对模(n)同余,记作(a equiv b)

4) Wilson定理(威尔逊定理)

当且仅当(p)为素数时 ((p-1)!equiv-1(mod p))

5) Fermat小定理(费马小定理)

如果(p)是一个素数,且((0<a<p)) 那么存在(a^{p-1}equiv1(mod p))

证明:

(1*a\%p=a_{1})

(2*a\%p=a_{2})

(dots)

((p-1)*a\%p=a_{p-1})

进行累乘

((p-1)!*a^{p-1}\%p=(p-1)!)

同除((p-1)!)(a^{p-1}equiv1(mod p))

[关于为什么(a_1*a_2* dots *a_{p-1}=(p-1)!)的解释] :

对于$iin [1,p-1] $ 有(a*i\%pequiv b)

((a*i\%p-b+p)\%pequiv 0)

((a*i-b) | p)

如果想找到另一个(i')使得(a*i'\%pequiv b) 那么只有(i'=i+p),但(i+p>p-1) 所以不存在这样的(i')

所以对于$iin [1,p-1] $ 集合(left {a_1,a_2, dots,a_{p-1} ight })等同于集合(left {1,2,dots,p-1 ight })

(a_1*a_2* dots *a_{p-1}=(p-1)!)

5) Euler定理(欧拉定理)

欧拉定理也是费马小定理的一个推广

我们定义(varphi (n))(iin [1,n])中有多少(i)使(gcd(n,i)=1)

如果(gcd(a,p)=1) 那么(a^{varphi(p)} equiv 1(mod p))

(当(p)是素数时,很明显(varphi(p)=p-1),就可以得到费马小定理了)

定理的证明和Fermat小定理几乎相同,只是要考虑的式子变成了所有与m互素的数的乘积

5) Fermat素数测试

Fermat素数测试属于一种随机算法

对于费马小定理来说,人们发现他的逆命题并不成立,比如(2^{560}\%561equiv1)(561)并不是个素数,(561=11*51)

人们把这样的数(n)叫做伪素数,即(2^{(n-1)}-1 | n)

对他进行推广,把(2)替换为任意的素数(a), 满足(a^{(n-1)}\%n=1)的合数(n)叫做以 (a) 为底的伪素数。

不满足(a^{(n-1)}\%n=1)(n)一定不是素数,我们一般是随机选取有限个数的底数 a ,对 n 进行素性测试。若全部满足,则认为数字 n 是质数,若有一个不满足,则认为数字 n 不是质数

这样的判断在一定程度上已经足够准确了

但,对于所有小于 (n) 的底数 (a),都满足(a^{(n-1)}\%n=1) 的数。(前(10)亿个数中,仅有(600)多个这样的数存在)这样的数叫做Carmichael数

利用二次探测定理可以对上面的素数判定算法作进一步改进,以避免将Carmichael数当作素数,而用这种方式优化过的素数测试算法叫做Miller_Rabin素数测试算法

原文地址:https://www.cnblogs.com/YangKun-/p/14344385.html