质数的定义:对于大于1的自然数,如果它的因子中只有1和它本身,则是一个质数也称素数。从定义可以看出质数的取值范围是从2开始的,小于2的数肯定不是质数。
质数的判定: 试除法
假设 d是n的一个因子,那么n/d 也是n的一个因子。因此我们只需要枚举小的因子,如果小的因子都除不尽,则是一个质数, d <= n/d 即 d <= 根号下n 时间复杂度 O(根号下n)
if (n < 2) return false;
for (int i = 2; i <= n/i; ++i){ // 注意这里的 i <= n/i 不要写成 i <= sqrt(n) 因为sqrt()函数比较慢
if (n % i == 0)
return false;
}
return true;
分解质因数:试除法
每个合数都可以写成几个质数相乘的形式,其中每个质数都是这个合数的因数,把一个合数用质因数相乘的形式表示出来 k = p1^a1 * p2^a2 * p3^a3 ...其中p1,p2,p3都是质因子(质数),叫做分解质因数。
如30=2×3×5 。分解质因数只针对合数,因为质数分解只能分解成1*n,而1又不是质数。
注意: n 中最多只包含一个大于根号下n的质因子,很明显如果有两个或者更多,那质因子相乘就大于n了。
void fun(int n){
for (int i = 2; i <= n/i; ++i){ // 一个数的大于根号下n的质因数最多只有一个,为了找出那一个甚至可能还不存在的质因子而循环n - 根号下n 次太浪费了。
int s = 0;
while(n % i == 0){ // 因为质数分解是将一个合数分解成质数,而连除一个质数的时候并不会影响别的质数,只会影响和该质数有关的合数。比如i == 2 且 n % i == 0 那就在n的因子中去除了2即2的幂次。
n /= i;
s += 1; // s是质因子出现的次数,也即是质因子的指数
}
if (s)
cout<<i<<" "<<s<<endl; // 质因子i 的幂次是 s
}
if (n > 1) cout<<n<<" "<<1<<endl; // 如果最后n == 1 说明所有的质因子在[2,根号下n]都找到了,当n > 1 时说明n此时就是大于根号n的质因子
puts("");
}
质数筛法: 给定一个数字n,求出从1到n中有多少个质数
埃氏筛法: 从头开始将所有质数以及它的倍数都给抹去,最后剩余的全都是质数
int fun(int n){
int st[n+1] = {0}; // 记录从2到n中的数有没有被抹去
int s = 0;
for (int i = 2; i <= sqrt(n + 0.5); ++i){
if (!st[i]){
s++;
int j = i * i;
while(j <= n){
st[j] = true; // 将i的倍数全不抹去
j += i;
}
}
}
return s; // s就是质素的个数
}
一个数的约数的求取: 试除法
vector<int> fun(int n){
vector<int> nums;
for (int i = 1; i <= n/i; ++i){ // 只需要枚举小的那一半约数就可以了
if (n % i == 0){
nums.push_back(i);
if (i != n/i) nums.push_back(n/i); // 如果 i == nums / i 的话 就只需要记录一个
}
}
sort(nums.begin(),nums.end());
return nums;
}
两数的最大公约数: 欧几里得算法
int gcd(int a,int b){
return b ? (b,a % b) : a;
}
return b ? gcd(b,a % b) : a;
当b == 0 的时候就是求 (a,0)的最大公约数,因为0能够整除所有得约数(约数中不含0),所有(a,0)的最大公约数为a.
当b == 0 的时候说明上一层的a % b == 0 也就是a == b,那么a,b都是最大公约数,而上一层的b传参数是当前层的a.
当b != 0的时候,gcd(a,b) 就是 gcd(b,a % b) gcd(a,b) 和 gcd(b,a % b) 的约数集合是相同的
如果c为a的约数同时也是b的约数的话,那么c就是ax + by 的约数,而 a % b 就是 a - by 因此c也是 a % b的约数
但是反过来: c是ax + by 的约数,而 a % c 不一定为0,b % c也不一定为0。 例如(4 - 1) % 3
组合数的常用公式:
质数与质数彼此之间是互质的,互质的两个数有一个性质: 如果一个数既能被p1整除,又能被p2整除,p1和p2又是互质的,那么这两个数的最小公倍数为: p1*p2
判断 ax + by = m 给定a > 0 和 b > 0 和 m 试判断 是否存在 正整数 x 和 y 使得 ax + by = m 成立
当 m % a = r 且 r % b = 0 时就说明 存在正整数 x = m / a , y = r / b 使得 ax + by = m 成立
ax + by = m 可以看成 ax + r(余数) = m , 也可以看成 r(余数) + by = m 这就证明了上面的一行。
也可以用dfs()暴力深搜,暴力打表前几项,依此来观察规律。
dfs(m,a,b){
if (!m) return true;
if (m){
if (m >= a && dfs(m - a,a,b)) return true;
if (m >= b && dfs(m - b,a,b)) return true;
}
return false;
}
求x的所有因子
for (int i = 1; i * i <= x; ++i) // i的取值范围是 [0,sqrt(x)],也就说明如果i * j == x 且i != j 则一定有一个大于sqrt(x),一定有一个小于sqrt(x)。
// 因此我们要获得某个数字的所有因子,就只需要枚举i(0 < i < sqrt(x))就行了,如果i != sqrt(x)的话,那么另外的一个因子就是 x / i
if (x % i == 0) { // 说明i是x的一个因子
ans[++cnt] = i;
if (i * i != x) ans[++cnt] = x / i; // 判断i是不是sqrt(x)
}
最小公倍数:
A,B的最小公倍数 = A * B / gcd(A,B)
以下素数默认为正的素数:
-1.两个整数互质:两个整数的公约数只有1
-2.如果a与b互素,a与c互素,充要于 a与bc互素
-3.p是素数,n是整数,如果p不能整数n的话,充要于 p和n互素(p不能整除n: n % p != 0,p本来的因子只有1和它 本身,n % p != 0 因此n和p的唯一的一个公共因子就是1,因此p和n互质)
-4.费马小定理: 如果p是质数,n是整数,一定有 p|(n^p - n) -> (n ^ p - n) % p == 0 -> (n^p) % p == n % p
-(1) 如果n是p的倍数,则 n^p % p == 0
-(2) 如果n不是p的倍数,则n^p % p = n % p -> n^(p - 1) % p = 1 % p -> n^(p - 1) 与 1 对p同余,则 (n^(p - 1)-1)% p == 0,n的逆元为 n^(p - 2)
-5.同余:给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b) % m == 0,那么就称整数a与b对模m同余,记作a≡b(mod m).
-数学上,两个整数除以同一个整数,若得相同余数,则二整数同余,但是反过来不恒成立,如 -3 和 7就是关于10同余的两整数.
-6. 同余的性质:
-1. a mod m == b mod m,c mod m == d mod m 则有(a + c) mod m == (b + d) mod m,(a - c) mod m == (b - d) mod m
-2. a mod m == b mod m,c mod m == d mod m 则有(a*c) mod m == (b*d) mod m
-3. 根据性质2就可推出: a mod m == b mod m 则有 a^n mod m == b^n mod m 以及 x*a mod m == x*b mod m (x是一个常数)
-4. 同余无除法性质