学习总结——第 8 章 数学

8.2 数论

8.2.1 模运算
  • (a + b) % m = ((a % m) + (b % m)) % m
  • (a - b) % m = ((a % m) - (b % m)) % m
  • (a * b) % m = ((a % m) * (b % m)) % m
  • 除法不适用
8.2.2 快速幂
8.2.2.1 分治法
// 用分治法求快速幂
#include <bits/stdc++.h>
using namespace std;

int fastPow(int a, int n){
	if(n == 0) return 1;
	if(n == 1) return a;
	int temp = fastPow(a, n >> 1);
	if(n % 2 == 1) return temp * temp * a;
	else return temp * temp;
}

int main(){
	int a, n;
	cin >> a >> n;
	
	cout << fastPow(a, n);
	return 0;
}
8.2.2.2 位运算
// 用位运算求快速幂
#include <bits/stdc++.h>
using namespace std;

int fastPow(int a, int n){
	int res = 1;
	while(n){
		if(n & 1) res *= a;
		a *= a;
		n >>= 1;
	}
	return res;
}

int main(){
	int a, n;
	cin >> a >> n;
	
	cout << fastPow(a, n);
	return 0;
}
8.2.2.3 对幂运算求模
// 对位运算求模
while(n){
		if(n & 1) res = (res * a) % MOD;
		a = a * a % MOD;
		n >>= 1;
}
8.2.2.4 矩阵快速幂
// 对矩阵快速幂
#include <iostream>
#include <string.h>
using namespace std;
const int MAXN = 2;
const int MOD = 1e4;
struct Matrix{
	int m[MAXN][MAXN];
	Matrix(){
		memset(m, 0, sizeof(m));
	}
};

Matrix Mulit(Matrix a, Matrix b){
	// 两个矩阵乘法
	Matrix res;
	for(int i = 0;i < MAXN;i ++)
		for(int j = 0;j < MAXN;j ++)
			for(int k = 0;k < MAXN;k ++)
				res.m[i][j] = (res.m[i][j] + a.m[i][k] * b.m[k][j]) % MOD;
	return res;
}
Matrix fastPow(Matrix a, int n){
	// 快速幂
	Matrix res;
	for(int i = 0;i < MAXN;i ++)
		res.m[i][i] = 1;
	while(n){
		if(n & 1) res = Mulit(res, a);
		a = Mulit(a, a);
		n >>= 1;
	}
	return res;
}
8.2.3 GCD LCM
8.2.3.1 最大公约数
// 求最大公约数
int gcd(int a, int b){
	return b == 0 ? a : gcd(b, a % b);
}
// 用 C++ 内置函数求最大公约数
std:__gcd(a, b);
8.2.3.2 最小公倍数
// 求最小公倍数
int lcm(int a, int b){
	return a / gcd(a, b) * b;
}
8.2.4 扩展欧几里得算法与二元一次方程的整数解

用扩展欧几里得算法求解 ax + by = gcd(a, b) 后,利用它可以进一步解任意方程 ax + by = n,得到一个整数解。步骤如下:

  1. 判断方程 ax + by = n 是否有整数解。有解的条件是 gcd(a, b) 可以整除 n;
  2. 用扩展欧几里得算法求 ax + by = gcd(a, b) 的一个解(x0, y0);
  3. 在 ax0 + by0 = gcd(a, b) 两边同时乘以 n / gcd(a, b),得:
            ax0n / gcd(a, b) + by0gcd(a, b) = n;
  4. 对照 ax + by = n ,得到它的一个解 (x0, y0) 是:
            x0 = x0n / gcd(a, b);
            y0 = y0n / gcd(a, b);

// 输入 a、b、n,求出符合条件的二元一次方程整数解
#include <bits/stdc++.h>
using namespace std;

void extend_gcd(int a,int b, int &x, int &y){
	if(b == 0){
		x = 1;
		y = 0;
		return;
	}
	extend_gcd(b, a % b, x, y);
	int tmp = x;
	x = y;
	y = tmp - (a / b) * y;
}

int gcd(int a, int b){
	return b == 0 ? a : gcd(b, a % b); 
}

int main(){
	int a, b, x, y, n;
	cin >> a >> b >> n;
	
	if(n % std::__gcd(a, b) != 0){
		cout << "没有整数解" << endl;
		return 0;
	}
	extend_gcd(a, b, x, y);
	
	cout << "A: " << x * n / gcd(a, b) << endl;
	cout << "B: " << y * n / gcd(a, b) << endl;
	return 0;
}
8.2.5 同余与逆元
8.2.5.1 同余
  1. 如果 a % m == b % m,则称 a 和 b 对于 m 同余,m 称同余的模。
  2. 同样理解为:m | (a - b),即 a - b 是 m 的整数倍。例如:6 | (23 - 5),23 和 5 对模 6 同余。
  3. 同余的符号记作:a ≡ \equiv b (mod m)
8.2.5.2 一元线性同余方程
  1. 因为 a ≡ \equiv b (mod m) ,所以 ax - b 是 m 的整数倍,设倍数为 y ,那么 ax - b = my。
8.2.5.3 逆元
  1. 方程 ax ≡ \equiv b (mod m) 的一个解 x ,称 x 为 a 模 m 的逆。这样的 x 有很多。
int mod_reverse(int a, int m){
	int x, y;
	extend_gcd(a, m, x, y);
	return (m + x % m) % m;
}
8.2.5.4 逆元与除法取模
  1. 设 b 的 逆元为 k;
  2. ( a b \frac{a}{b} ba) mod m = (( a b \frac{a}{b} ba) mod m) ((bk) mod m) = ( a b \frac{a}{b} babk) mod m = (ak) mod m;
8.2.5.5 逆元求解二元一次方程 ax + my = b
步骤求解方程 ax + my = b
同余方程 ax ≡ \equiv b (mod m)
例:求解 8x + 31y = 24
同余方程是 8x ≡ \equiv 24 (mod 31)
a = 8,b = 24,m = 31
1有界的条件:gcd(a, m) 能整除 bgcd(8, 31) = 1 能整除 24
2ax ≡ \equiv 1 (mod m) 的逆元 a ,等价
于用扩展欧几里得算法求解 ax + my = 1
8x + 31y = 1 的一个解是
x = 4,y = -1即一个逆元是 a = 4
3一个特解是 x = abx = a b = 4 * 24 = 96
4带入方程 ax + my = b,求解 y代入 8x + 31y = 24,得到 y = -24
8.2.6 素数
8.2.6.3 用埃式素数筛求素数数量
// 埃式素数筛求素数数量
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e7;
int prime[MAXN + 1];
int visited[MAXN + 1];

int e_sieve(int n) {
	int k = 0;
	for(int i = 0;i <= n;i ++) visited[i] = false;
	for(int i = 2;i <= n;i ++)
		if(!visoted[i]){
			prime[k ++];
			for(int j = 2 * i;j <= n;j += i) visited[j] = true;
		}
	return k;
}
// 优化后的埃式素数筛
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e7;
int prime[MAXN + 1];
int visited[MAXN + 1];

int e_sieve(int n) {
	for(int i = 0;i <= n;i ++) visited[i] = false;
	for(int i = 2;i * i <= n;i ++)
		if(!visited[i])
			for(int j = i * i;j <= n;j += i) visited[j] = true;
	
	int k = 0;
	for(int i = 2;i <= n;i ++)
		if(!visited[i])
			prime[k ++];
	return k;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值