数论基础知识(数论第一波,欧拉筛骚操作)


前言

数论中所有的数通常都是正整数,在出现的字母在未经说明的情况下为正整数

模运算

有些时候答案非常大,题目会要求你输出答案取模一个数的值
对于取模,有以下定理
1、 ( a + b ) % c = ( a % c + b % c ) % c (a+b)\%c=(a\%c+b\%c)\%c (a+b)%c=(a%c+b%c)%c
2、 ( a − b ) % c = ( a % c − b % c ) % c (a-b)\%c=(a\%c-b\%c)\%c (ab)%c=(a%cb%c)%c
3、 ( a ∗ b ) % c = ( a % c ) ∗ ( b % c ) % c (a*b)\%c=(a\%c)*(b\%c)\%c (ab)%c=(a%c)(b%c)%c

对于符号,我们可以简化成语言
和的余数等于余数的和,差的余数等于余数的差,积的余数等于余数的积。
肯定有人问:“为什么没有商的余数等于余数的商”
对于除法而言,及时除数与被除数都为整数,但商也不一定是整数,而加减乘在 a , b a,b a,b均为整数的情况下一定是整数

整除

a ≠ 0 a≠0 a=0,若存在整数 q ≠ 0 q≠0 q=0使得 a q = b aq=b aq=b,那么称a是b的因数(约数),b是a的倍数,a能整除b,b能被a整除,记为 a ∣ b a|b ab
对于整除,有以下定理
1、 a ∣ b , b ∣ c ⇒ a ∣ c a|b,b|c\Rightarrow a|c abbcac,a是b的因子,b是c的因子,那么a也就是c的因子
2、 a ∣ b , c ∣ d ⇒ a c ∣ b d a|b,c|d\Rightarrow ac|bd abcdacbd,a是b的因子,c是d的因子,那么ab也就是cd的因子
3、 a ∣ b , a ∣ c ⇒ a ∣ p b + p c ,过程: b = n a , c = m a ,原式等于 a ∣ p n a + p m a ,等于 a ∣ a ( p n + p m ) , ∵ a ∣ a , ∴ a ∣ p b + p c a|b,a|c\Rightarrow a|pb+pc,过程:b=na,c=ma,原式等于a|pna+pma,等于a|a(pn+pm),∵a|a,∴a|pb+pc abacapb+pc,过程:b=nac=ma,原式等于apna+pma,等于aa(pn+pm)aaapb+pc

质数(prime number,又称素数)

  • 质数定义:不含有除了1和自身以外的其他因子的数称为质数(素数)
  • 特殊:2是最小的质数,也是唯一的偶质数
  • 质数判定定理:若一个数n找不到小于等于 n \sqrt{n} n 的非1因数,则这个数是质数
  • 素数定理:n充分大时,n以内的素数个数约为n/log2n个
    关于质数的东西有很多呀,不慌,慢慢来
整数的标准分解

一个大于1的整数一定可以唯一地写成若干个质数的幂的积
就像这样 n = p 1 w 1 ∗ p 2 w 2 ∗ p 3 w 3 ∗ p 4 w 4 ∗ … … ∗ p m w m n=p_1^{w1}*p_2^{w2}*p_3^{w3}*p_4^{w4}*……*p_m^{wm} n=p1w1p2w2p3w3p4w4……pmwm

  • 互质(coprime):两个整数除1以外再没有其他因数,那么这两个数互质
  • 两个互质的数的唯一分解中没有相同的质数
代码
void factorize(int n){
    for(int i = 2; n != 1; i ++){
        if( n%i == 0 ){
            p[++k] = i;
            while( n%i == 0 ){
                n /= i;
                w[k]++
            }
        }
    }
}
最大公约数与最小公倍数
  • 两个数 a , b a,b a,b的最大公约数记为 g c d ( a , b ) gcd(a,b) gcd(a,b)或者 ( a , b ) (a,b) (a,b)(记住共产党)
  • 两个数 a , b a,b a,b的最小公倍数记为 l c m ( a , b ) lcm(a,b) lcm(a,b)或者 [ a , b ] [a,b] [a,b]

我们用整数的标准分解来深度了解一下 g c d gcd gcd l c m lcm lcm
x = p 1 a 1 ∗ p 2 a 2 ∗ p 3 a 3 ∗ p 4 a 4 ∗ … … ∗ p m a m x=p_1^{a1}*p_2^{a2}*p_3^{a3}*p_4^{a4}*……*p_m^{am} x=p1a1p2a2p3a3p4a4……pmam
y = p 1 b 1 ∗ p 2 b 2 ∗ p 3 b 3 ∗ p 4 b 4 ∗ … … ∗ p n b n y=p_1^{b1}*p_2^{b2}*p_3^{b3}*p_4^{b4}*……*p_n^{bn} y=p1b1p2b2p3b3p4b4……pnbn
其中 p n p_n pn p m p_m pm足够大, a i , b i a_i,b_i aibi可以为0
我们知道两个数的 g c d gcd gcd两个数都有最大因子,注意,是最大,说明 p x p_x px一定取 p x a x p_x^{ax} pxax p x b x p_x^{bx} pxbx,而两个数都有,说明取 p x m i n ( a x , b x ) p_x^{min(ax,bx)} pxmin(ax,bx)
o = m a x ( n , m ) o = max(n,m) o=max(n,m)
g c d ( x , y ) = p 1 m i n ( a 1 , b 1 ) ∗ p 2 m i n ( a 2 , b 2 ) ∗ p 3 m i n ( a 3 , b 3 ) ∗ … … ∗ p o m i n ( a o , b o ) gcd(x,y)=p_1^{min(a1,b1)}*p_2^{min(a2,b2)}*p_3^{min(a3,b3)}*……*p_o^{min(ao,bo)} gcd(x,y)=p1min(a1,b1)p2min(a2,b2)p3min(a3,b3)……pomin(ao,bo)
而两个数的 l c m lcm lcm既有因子 x x x,又有因子 y y y, 说明 l c m lcm lcm p 1 x p1_x p1x一定满足 p x m a x ( a x , b x ) ∣ p 1 x p_x^{max(ax,bx)}|p1_x pxmax(ax,bx)p1x,但又要求最小,所以 p 1 x p1_x p1x p x m a x ( a x , b x ) p_x^{max(ax,bx)} pxmax(ax,bx)
l c m [ x , y ] = p 1 m a x ( a 1 , b 1 ) ∗ p 2 m a x ( a 2 , b 2 ) ∗ p 3 m a x ( a 3 , b 3 ) ∗ … … ∗ p o m a x ( a o , b o ) lcm[x,y]=p_1^{max(a1,b1)}*p_2^{max(a2,b2)}*p_3^{max(a3,b3)}*……*p_o^{max(ao,bo)} lcm[x,y]=p1max(a1,b1)p2max(a2,b2)p3max(a3,b3)……pomax(ao,bo)
而显然 ( x , y ) ∗ [ x , y ] = x ∗ y (x,y)*[x,y] = x*y (x,y)[x,y]=xy

约数个数与约数和

我们从整数的唯一分解入手
x = p 1 a 1 ∗ p 2 a 2 ∗ p 3 a 3 ∗ p 4 a 4 ∗ … … ∗ p m a m x=p_1^{a_1}*p_2^{a_2}*p_3^{a_3}*p_4^{a_4}*……*p_m^{a_m} x=p1a1p2a2p3a3p4a4……pmam
我们可以知道,既然 p 1 a 1 ∣ x p_1^{a_1}|x p1a1x,说明 p 1 0 ∣ x p_1^{0}|x p10x p 1 1 ∣ x p_1^{1}|x p11x p 1 2 ∣ x p_1^{2}|x p12x…… p 1 a 1 ∣ x p_1^{a_1}|x p1a1x,而这里就有 a 1 + 1 a_1+1 a1+1个约数
而既然 p 2 a 2 ∣ x p_2^{a_2}|x p2a2x,说明就有 a 2 + 1 a_2+1 a2+1个约数,后面以此类推,而前面 a n + 1 a_n+1 an+1约数可以与后面 a m + 1 a_m+1 am+1个约数逐个组合,根据乘法原理,就有 ( a n + 1 ) ∗ ( a m + 1 ) (a_n+1)*(a_m+1) (an+1)(am+1)个约数
而根据以上结论,就可以推出 x x x的约数个数为 d [ x ] = ( a 1 + 1 ) ∗ ( a 2 + 1 ) ∗ ( a 3 + 1 ) … … ∗ ( a m + 1 ) d[x]=(a_1+1)*(a_2+1)*(a_3+1)……*(a_m+1) d[x]=(a1+1)(a2+1)(a3+1)……(am+1)
而我们知道 x x x p 1 0 ∣ x p_1^{0}|x p10x p 1 1 ∣ x p_1^{1}|x p11x p 1 2 ∣ x p_1^{2}|x p12x…… p 1 a 1 ∣ x p_1^{a_1}|x p1a1x这a_1+1个约数,而且对于每一个 x x x的质因子都有 a i + 1 a_i+1 ai+1个约数,而这 a 1 + a 2 + … … a m + m a_1+a_2+……a_m+m a1+a2+……am+m个约数可以多个组合,因式分解一下就可得到 s [ x ] = ( 1 + p 1 1 + p 1 2 … + p 1 a 1 ) ∗ ( 1 + p 2 1 + p 2 2 … + p 2 a 2 ) … ∗ ( 1 + p m 1 + p m 2 … + p m a m ) s[x] = (1+p_1^{1}+p_1^{2}…+p_1^{a_1})*(1+p_2^{1}+p_2^{2}…+p_2^{a_2})…*(1+p_m^{1}+p_m^{2}…+p_m^{a_m}) s[x]=(1+p11+p12+p1a1)(1+p21+p22+p2a2)(1+pm1+pm2+pmam)
我们设 ( 1 + p i 1 + p i 2 … + p i a i ) = Q (1+p_i^{1}+p_i^{2}…+p_i^{a_i}) = Q (1+pi1+pi2+piai)=Q ( 1 ) (1) (1)式,则 p i ∗ Q = ( p i 1 + p i 2 … + p i a i + 1 ) p_i*Q=(p_i^{1}+p_i^{2}…+p_i^{a_i+1}) piQ=(pi1+pi2+piai+1) ( 2 ) (2) (2)式,
∴ ( 2 ) − ( 1 ) = p i ∗ Q − Q = ( p i − 1 ) ∗ Q = p i a i + 1 − 1 ∴(2)-(1)=p_i*Q-Q=(p_i-1)*Q=p_i^{a_i+1}-1 (2)(1)=piQQ=(pi1)Q=piai+11
∴ Q = p i a i + 1 − 1 p i − 1 ∴Q=\frac{p_i^{a_i+1}-1}{p_i-1} Q=pi1piai+11

欧拉筛法

埃拉托尼斯筛法相对于欧拉筛法而言太不实用,请读者自主学习
欧拉筛法如下:

void sieve(int x){
    for(int i = 2; i <= n; i ++){
        if( !v[i] ){
            p[++cnt] = i;
            v[i] = 1;
        }
        for(int j = 1; j <= cnt&&i*p[j] <= x; j ++){
            v[i*p[j]] = 1;
            if( i % p[i] ==  0)
                break;
        }
    }
}

我相信有很多读者不明白第二个循环,其实无论此时 i i i是否为质数,我们都需要把之前筛出来的素数乘 i i i来筛掉后面的素数,而欧拉筛的难点就在于对if (i % prime[j] == 0)这步的理解,当i是prime[j]的整数倍时,记 m = i / prime[j],那么 i * prime[j+1] 就可以变为 (m * prime[j+1]) * prime[j],这说明 i * prime[j+1] 是 prime[j] 的整数倍,不需要现在筛出,因为在之后筛除过程中i * prime[j+1] 这个合数一定会被prime[j]筛除,prime[j]之后的所有素数同理,所以break跳出循环。

欧拉函数求约数个数d[n]
  • n n n是素数,约数只有 1 , n 1,n 1,n,所以 d [ n ] = 2 d[n]=2 d[n]=2
  • i % p [ j ] ≠ 0 i\%p[j]\ne0 i%p[j]=0 i i i不存在 p [ j ] p[j] p[j]这个因子,说明 i ∗ p [ j ] i*p[j] ip[j]只包含 p [ j ] p[j] p[j]的一次方,没问题吧,而我们知道约数个数的公式是乘上每个质因子的次数+1,因为 i ∗ p [ j ] i*p[j] ip[j]只包含 p [ j ] p[j] p[j]的一次方, p [ j ] p[j] p[j]的次数也就是一,乘上的也就是 ( 1 + 1 ) = 2 (1+1)=2 (1+1)=2
  • i % p [ j ] = 0 i\%p[j]=0 i%p[j]=0 i i i至少存在 p [ j ] p[j] p[j]的一次方,说明 i ∗ p [ j ] i*p[j] ip[j]至少包含 p [ j ] p[j] p[j]的二次方,没问题吧,我们用 n u m [ i ] num[i] num[i]表示 i i i的最小的质因子的次数(因为我们需要通过次数来计算约数个数),则 d [ i ] d[i] d[i]包含了 ( 1 + n u m [ i ] ) (1+num[i]) 1+num[i]这个因式,因为 d [ i ] d[i] d[i]肯定也是从之前的某个数乘上 ( 1 + n u m [ i ] ) (1+num[i]) (1+num[i])得到的,而现在要求 d [ i ∗ p [ j ] d[i*p[j] d[ip[j],可以肯定的是 d [ i ∗ p [ j ] ] d[i*p[j]] d[ip[j]]肯定存在 n u m [ i ] + 2 num[i]+2 num[i]+2这个因式,而 d [ i ] d[i] d[i]存在 n u m [ i ] + 1 num[i]+1 num[i]+1这个因式,那么如何转换呢,就是先把 n u m [ i ] + 1 num[i]+1 num[i]+1除了之后,再乘上 n u m [ i ] + 2 num[i]+2 num[i]+2,就可以推出 d [ i ∗ p [ j ] ] d[i*p[j]] d[ip[j]]
    因为 i ∗ p [ j ] i*p[j] ip[j]是在 i i i的基础上增加了 p p p的一次方,所以 n u m [ i ∗ p [ j ] ] = n u m [ i ] + 1 num[i*p[j]]=num[i]+1 num[ip[j]]=num[i]+1
    所以 n u m [ i ∗ p [ j ] ] = n u m [ i ] + 1 d [ i ∗ p [ j ] ] = d [ i ] / ( n u m [ i ] + 1 ) ∗ ( n u m [ i ∗ p [ j ] ] + 1 ) num[i*p[j]] = num[i]+1\\ d[i*p[j]] = d[i]/(num[i]+1)*(num[i*p[j]]+1) num[ip[j]]=num[i]+1d[ip[j]]=d[i]/(num[i]+1)(num[ip[j]]+1)

代码

void sieve(int x){
    d[1] = 1;
    for(int i = 2; i <= n; i ++){
        if( !v[i] ){
            p[++cnt] = i;
            v[i] = 1;
            d[i] = 2;
        }
        for(int j = 1; j <= cnt&&i*p[j] <= x; j ++){
            v[i*p[j]] = 1;
            if( i % p[i] ==  0){
                num[i*p[j]] = num[i]+1;
                d[i*p[j]] = d[i]/(num[i]+1)*(num[i]+2);
                break;
            }
            d[i*p[j]] = d[i]*2;
            num[i*p[j]] = num[i]+1;
        }
    }
}
欧拉函数求约数和s[n]
  • i i i为质数,约数只有 i , 1 i, 1 i,1,所以 s [ i ] = i + 1 s[i] = i+1 s[i]=i+1
  • i % p [ j ] ≠ 0 i\%p[j]\ne0 i%p[j]=0,说明 i ∗ p [ j ] i*p[j] ip[j]只含有 p [ j ] p[j] p[j]的一次方,没问题吧。而因为我们知道
    求约数和,就是求每个质因子等比数列的乘积,因为 i ∗ p [ j ] i*p[j] ip[j]只含有 p [ j ] p[j] p[j]的一次方,所以要在 s [ i ] s[i] s[i]基础上乘的就是 p [ j ] 1 p[j]^1 p[j]1的等比数列,也就是 p [ j ] 1 + p [ j ] 0 = p [ j ] + 1 p[j]^1+p[j]^0=p[j]+1 p[j]1+p[j]0=p[j]+1
  • i % p [ j ] = 0 i\%p[j]=0 i%p[j]=0,说明 i ∗ p [ j ] i*p[j] ip[j]至少含有 p [ j ] p[j] p[j]的二次方,我们设 p s u m [ i ] psum[i] psum[i]表示关于 i i i的最小质因子 p p p的等比数列求和 1 + p + p 2 + … … + p w 1+p+p^2+……+p^w 1+p+p2+……+pw因为约数和就是这东西的乘积,可以肯定的是, s [ i ] = p s u m [ i ] s[i]=psum[i] s[i]=psum[i]乘上另外质因子的等比数列求和。由于 i ∗ p [ j ] i*p[j] ip[j] i i i均以 p [ j ] p[j] p[j]作为最小的质因子(欧拉筛的性质,自己看代码体会吧),所以 i ∗ p [ j ] i*p[j] ip[j]一定包含 p s u m [ i ] ∗ p + 1 psum[i]*p+1 psum[i]p+1这个因式(因为 i ∗ p [ j ] i*p[j] ip[j] p [ j ] p[j] p[j]多一个 p [ j ] p[j] p[j]的1次方, p s u m [ i ] = 1 + p + p 2 + … … + p w psum[i]=1+p+p^2+……+p^w psum[i]=1+p+p2+……+pw,所以 p s u m [ i ∗ p [ j ] ] = 1 + p + p 2 + … … + p w + 1 psum[i*p[j]]=1+p+p^2+……+p^{w+1} psum[ip[j]]=1+p+p2+……+pw+1,所以 p s u m [ i ∗ p [ j ] ] psum[i*p[j]] psum[ip[j]]其实就等于 p s u m [ i ] ∗ p [ j ] + 1 psum[i]*p[j]+1 psum[i]p[j]+1,看的出来吧),那么 s [ i ∗ p [ j ] ] s[i*p[j]] s[ip[j]] s [ i ] s[i] s[i]的转换就和 d [ i ∗ p [ j ] ] d[i*p[j]] d[ip[j]] d [ i ] d[i] d[i]的转换差不多了
    p s u m [ i ∗ p [ j ] ] = p s u m [ i ] ∗ p [ j ] + 1 psum[i*p[j]] = psum[i]*p[j]+1 psum[ip[j]]=psum[i]p[j]+1
    s [ i ∗ p [ j ] ] = s [ i ] p s u m [ i ] ∗ ( p s u m [ i ∗ p [ j ] ] ) s[i*p[j]]=\frac{s[i]}{psum[i]}*(psum[i*p[j]]) s[ip[j]]=psum[i]s[i](psum[ip[j]])
    代码
void sieve(int x){
    s[1] = 1;
    for(int i = 2; i <= x; i ++){
        if( !v[i] ){
            p[++cnt] = i;
            v[i] = 1;
            psum[i] = s[i] = i+1;
        }
        for(int j = 1; j <= cnt&&p[j]*i <= x; j ++){
            v[i*p[j]] = 1;
            if( i%p[j] == 0 ){
                psum[i*p[j]] = psum[i]*p[j]+1;
                s[i*p[j]] = s[i]/psum[i]*psum[i*p[j]];
                break;
            }
            s[i*p[j]] = s[i]*(p[j]+1);
        	psum[i*p[j]] = 1+p[j];
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值