初等数论——素数

基础
概念

整除:如果整数 b b b可以表示成整数 a a a的整数 k k k倍,即 b = k a ( a , b , c ∈ Z ) b=ka(a,b,c\in Z) b=ka(a,b,cZ),则称 b b b a a a整除或 a a a整除 b b b,记作 a ∣ b a|b ab

最大公约数:若 a , b ∈ N ∗ a,b\in N^* a,bN ,则 ( a , b ) (a,b) (a,b)表示最大的正整数 d d d,使得 d ∣ a ∧ d ∣ b d|a \land d|b dadb,成为 a , b a,b a,b的最大公约数。特别的,规定任意正整数 a a a,有 ( a , 0 ) = a (a,0)=a (a,0)=a

素数

概念:除了 1 1 1与其本身外,无其它约数的正整数。特别地,1既不是素数也不是合数。

判定

判定正整数 n ( n > 1 ) n(n>1) n(n>1)是否为素数

  • 枚举法

    2 2 2枚举至 n − 1 n-1 n1, 若其中存在数能整除 n n n,则 n n n为合数,否则 n n n为素数。复杂度 O ( n ) \Omicron(n) O(n)

    小优化:若 d ∣ n d|n dn,则必有 n d ∣ n \frac {n}{d}|n dnn,因此 n n n的约数成对存在,且乘积为 n n n。任选一对约数 d 1 ⋅ d 2 = n d1\cdot d2=n d1d2=n,若 d 1 > n ∧ d 2 > n d1> \sqrt n \land d2> \sqrt n d1>n d2>n ,则 d 1 ⋅ d 2 > n d1\cdot d2>n d1d2>n d 1 ⋅ d 2 = n d1\cdot d2=n d1d2=n相矛盾,因此 n n n的任意一对约数 d 1 ≤ d 2 d1\leq d2 d1d2,必有 d 1 ≤ n d1\leq \sqrt n d1n . 又由于约数成对存在,因此我们仅需枚举 2 2 2 n \sqrt n n 判断是否存在 n n n的约数即可。复杂度 O ( n ) O(\sqrt n) O(n )

  • 素数测试

    费马素数测试

    费马小定理:对于任意素数 p p p,若 p ∤ a p\not|a pa,则有 a p − 1 ≡ 1 ( m o d   p ) a^{p-1} \equiv 1(mod \ p) ap11(mod p)

容易想到可以通过选取随机数检验费马小定理来判定 n n n是否是素数。但费马小定理逆定理并不成立,即使 a p − 1 ≡ 1 ( m o d   p ) a^{p-1}\equiv 1(mod\ p) ap11(mod p), p p p也未必是素数,我们将满足该条件的合数称为伪素数或卡迈尔数

Miller-Rabin 素数测试

二次探测定理:若 p p p为奇素数,则 x 2 ≡ 1 ( m o d   p ) x^2\equiv 1(mod\ p) x21(mod p)解为 x ≡ 1 x\equiv 1 x1 x ≡ p − 1 x\equiv p-1 xp1.移项因式分解易证。

费马小定理结合二次探测定理,对于 n − 1 n-1 n1,我们先分解成 n − 1 = n 0 ⋅ 2 t n-1=n_0 \cdot 2^t n1=n02t,然后先求出 c = p n 0 c=p^{n_0} c=pn0,然后对 c c c进行 t t t次自平方操作,若出现非平凡平方根(即 1 1 1 n − 1 n-1 n1之外的数),则不是素数,否则通过测试

参考代码:

inline bool Miller_Rabin(ll x) {
	if (x<3 || x%2==0) return (x==2);
	ll a=x-1, b=0;
	while (a%2==0) a>>=1, ++b;
	for (R ll i=1; i<=10; i++) {
		ll c=rand()%(x-1)+1;
		c=quick_pow(c, a, x);
		if (c==1) continue;
		ll j;
		for (j=0; j<b; j++) {
			if (c==x-1) break;
			c=(el)c*c%x;
		}
		if (j>=b) return false;
	}
	return true;
}
筛法
  • Eratosthenes筛(埃筛)

    目的是筛出 2 − n 2-n 2n内所有素数。素数即除 1 1 1与其本身外没有其它约数的正整数。因此我们可以通过约数否决掉一个数是素数的可能性。每遍历到一个素数,枚举它的整数倍,将其倍数全部排除.复杂度 O ( n l o g l o g n ) \Omicron(nloglogn) O(nloglogn)

    int prime[N], cnt;
    bool book[N];
    inline void get_prime(int n) {
        for (int i=2; i<=n; i++) {
            if (book[i]) continue;
            prime[++cnt]=i;
            for (int j=i; j<=n; j+=i) book[j]=true;
        }    
    }
    
  • 欧拉筛

如果每个合数都只标记一次,那复杂度就是线性的了。详见 O I − w i k i OI-wiki OIwiki代码解释.复杂度 O ( n ) \Omicron(n) O(n)

```cpp
inline void euler(){
    for(R ll i=2;i<=n;i++){
        if(!v[i]){
            v[i]=i;
            prime[++sum]=i;
        }
        for(R ll j=1;j<=sum&&prime[j]<=v[i]&&prime[j]*i<=n;j++){
            v[prime[j]*i]=prime[j];
            if (i%prime[j]==0) break;
        }
      }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值