前言
数论中所有的数通常都是正整数,在出现的字母在未经说明的情况下为正整数
模运算
有些时候答案非常大,题目会要求你输出答案取模一个数的值
对于取模,有以下定理
1、
2、
3、
对于符号,我们可以简化成语言
和的余数等于余数的和,差的余数等于余数的差,积的余数等于余数的积。
肯定有人问:“为什么没有商的余数等于余数的商”
对于除法而言,及时除数与被除数都为整数,但商也不一定是整数,而加减乘在
均为整数的情况下一定是整数
整除
,若存在整数
使得
,那么称a是b的因数(约数),b是a的倍数,a能整除b,b能被a整除,记为
对于整除,有以下定理
1、
,a是b的因子,b是c的因子,那么a也就是c的因子
2、
,a是b的因子,c是d的因子,那么ab也就是cd的因子
3、
质数(prime number,又称素数)
- 质数定义:不含有除了1和自身以外的其他因子的数称为质数(素数)
- 特殊:2是最小的质数,也是唯一的偶质数
- 质数判定定理:若一个数n找不到小于等于 的非1因数,则这个数是质数
- 素数定理:n充分大时,n以内的素数个数约为n/log2n个
关于质数的东西有很多呀,不慌,慢慢来
1、整数的标准分解
一个大于1的整数一定可以唯一地写成若干个质数的幂的积
就像这样
- 互质(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、最大公约数与最小公倍数
- 两个数
的最大公约数记为
或者
(记住共产党) - 两个数 的最小公倍数记为 或者
我们用整数的标准分解来深度了解一下
和
其中
和
足够大,
可以为0
我们知道两个数的
是两个数都有的最大因子,注意,是最大,说明
一定取
或
,而两个数都有,说明取
设
∴
而两个数的
是既有因子
,又有因子
, 说明
的
一定满足
,但又要求最小,所以
取
∴
而显然
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;
}
}
}
我相信有很多读者不明白第二个循环,其实无论此时 是否为质数,我们都需要把之前筛出来的素数乘 来筛掉后面的素数,而欧拉筛的难点就在于对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]
- 若 是素数,
- 若 , 不存在 这个因子,说明 只包含 的一次方,所以
- 若
,
至少存在
的一次方,说明
至少包含
的二次方,我们用
表示
的最小的质因子的次数,则
包含了
这个因式,由于
和
均以
作为最小质因子,那么
一定包含
这一因式
且不难看出
代码
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;
}
}
}