数论基础知识(数论第一波)

前言

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

模运算

有些时候答案非常大,题目会要求你输出答案取模一个数的值
对于取模,有以下定理
1、 ( 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
3、 ( a b ) % c = ( a % c ) ( b % c ) % c (a*b)\%c=(a\%c)*(b\%c)\%c

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

整除

a 0 a≠0 ,若存在整数 q 0 q≠0 使得 a q = b aq=b ,那么称a是b的因数(约数),b是a的倍数,a能整除b,b能被a整除,记为 a b a|b
对于整除,有以下定理
1、 a b b c a c a|b,b|c\Rightarrow a|c ,a是b的因子,b是c的因子,那么a也就是c的因子
2、 a b c d a c b d a|b,c|d\Rightarrow ac|bd ,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

质数(prime number,又称素数)

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

1、整数的标准分解

一个大于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}

  • 互质(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]++
            }
        }
    }
}

2、最大公约数与最小公倍数

  • 两个数 a , b a,b 的最大公约数记为 g c d ( a , b ) gcd(a,b) 或者 ( a , b ) (a,b) (记住共产党)
  • 两个数 a , b a,b 的最小公倍数记为 l c m ( a , b ) lcm(a,b) 或者 [ a , b ] [a,b]

我们用整数的标准分解来深度了解一下 g c d gcd l c m 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}
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}
其中 p n p_n p m p_m 足够大, a i b i a_i,b_i 可以为0
我们知道两个数的 g c d gcd 两个数都有最大因子,注意,是最大,说明 p x p_x 一定取 p x a x p_x^{ax} p x b x p_x^{bx} ,而两个数都有,说明取 p x m i n ( a x , b x ) p_x^{min(ax,bx)}
o = m a x ( 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)}
而两个数的 l c m lcm 既有因子 x x ,又有因子 y y , 说明 l c m lcm p 1 x p1_x 一定满足 p x m a x ( a x , b x ) p 1 x p_x^{max(ax,bx)}|p1_x ,但又要求最小,所以 p 1 x p1_x p x m a x ( a x , b x ) p_x^{max(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)}
而显然 ( x , y ) [ x , y ] = x y (x,y)*[x,y] = x*y

3、欧拉筛法

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

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 来筛掉后面的素数,而欧拉筛的难点就在于对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 是素数, d [ n ] = 2 d[n]=2
  • i % p [ j ] 0 i\%p[j]\ne0 i i 不存在 p [ j ] p[j] 这个因子,说明 i p [ j ] i*p[j] 只包含 p [ j ] p[j] 的一次方,所以 d [ i p [ j ] ] = d [ i ] 2 d[i*p[j]] = d[i]*2
  • i % p [ j ] = 0 i\%p[j]=0 i i 至少存在 p [ j ] p[j] 的一次方,说明 i p [ j ] i*p[j] 至少包含 p [ j ] p[j] 的二次方,我们用 n u m [ i ] num[i] 表示 i i 的最小的质因子的次数,则 d [ i ] d[i] 包含了 1 + n u m [ i ] (1+num[i]) 这个因式,由于 i p r i m e [ j ] i*prime[j] i i 均以 p r i m e [ j ] prime[j] 作为最小质因子,那么 i p r i m e [ j ] i*prime[j] 一定包含 ( 1 + n u m [ i ] + 1 ) (1+num[i]+1) 这一因式
    且不难看出 n u m [ i p r i m e [ j ] ] = n u m [ i ] + 1 num[i*prime[j]]=num[i]+1 d [ i p [ j ] ] = d [ i ] n u m [ i ] + 1 ( n u m [ i ] + 2 ) d[i*p[j]]=\frac{d[i]}{num[i]+1}*(num[i]+2)
    代码
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]] = 1;
        }
    }
}
欧拉函数求约数和s[n]

猜你喜欢

转载自blog.csdn.net/zyz_bz/article/details/88180823