数论

  1. 一些数论基本定理
    ① 合成律
    ( a + b ) mod c ≡ ((a mod c) + (b mod c)) mod c
    ( a * b ) mod c ≡ ((a mod c) * (b mod c)) mod c
    ② 消去律
    若 gcd (c,p ) = 1,则ac ≡ bc mod p => a b mod p
    下面给出证明:
    ac ≡ bc mod p => ac = bc + kp => c(a - b) = kp,c 和 p 互质=>
    (1) c 能整除 k 或 (2) a = b
    如果(2)不成立,则 c|kp
    c 和 p 没有公因子 => c|k ,所以 k = ck’ => c(ab)= kp 可以表示为 c(ab) = ck’p
    因此,ab = k’p ,得出 a ≡ b mod p
  2. 快速幂取模
    代码:
int PowMod (int a, int b, int c)
{
	//快速求 a^b % c ,要避免计算中间结果溢出
	int result = 1;
	int base = a % c
	while (b) {
		if (b & 1)
			result = (result * base) % c;
		base = (base * base) % c;
		b >>= 1;
	}
	return result;
}
  1. Sn = a+a^2 +…+a^n,要求Sn mod p。
    (1) 若 n 是偶数
    在这里插入图片描述
    (2) 若 n 是奇数
    在这里插入图片描述
    代码实现:
struct Matrix
{
	int m[maxn][maxn];
}result, base;
Maxtrix Mul(Matrix A, Matrix B, int n)
{
	Matrix tmp;//定义一个临时的矩阵,存放A*B的结果
	memset(tmp.m, 0, sizeof(tmp.m));
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			for (int k = 1; k <= n; k++)
			{
				tmp.m[i][j]+=A.m[i][k] * B.m[k][j];
			}
		}
	}
	return temp;
}
  1. 矩阵快速幂 + 等比数列二分求和取模
    首先我们来了解一下矩阵的乘法用代码 该如何表示:
    设矩阵A,B为 n 阶方阵,那我们都知道
    在这里插入图片描述
    很显然,这里使用一个三循环就可以实现的,下面上代码:
void QuickPow(int n, int x)
{
	/*整数的快速幂ans初始化为1,对于矩阵快速幂,ans应该初始化为单位矩阵*/
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (i == j) 
			{
				result.m[i][j] = 1;
			}
			else
			{
				result.m[i][j] = 0;
			}
		}
	} 
	while (x)
	{
		if (x & 1)
		{
			result = Mul(result, base);
		}
		res = Mul(base, base);
		x >>= 1;
	}
}

下面实现矩阵快速幂:

void QuickPow(int n, int x)
{
	/*整数的快速幂ans初始化为1,对于矩阵快速幂,ans应该初始化为单位矩阵*/
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= n; j++)
		{
			if (i == j) 
			{
				ans.m[i][j] = 1;
			}
			else
			{
				ans.m[i][j] = 0;
			}
		}
	} 
	while (x)
	{
		if (x & 1)
		{
			ans = Mul(ans, res);
		}
		res = Mul(res, res);
		x >>= 1;
	}
}
  1. 欧几里得算法求最大公约数
int gcd(int x, int y)
{
	return y == 0 ? x : gcd(y, x % y);
}

由此也可以求出最小公倍数:lcm(x, y) = x * y * gcd(x, y)
     6. 扩展欧几里得算法
ax+by = gcd (a,b) 有整数解 x,y
<=>bx + (a%b)y = gcd (a,b ) 有整数解 (x1, y1),且
ax+by = gcd (a,b) 中的x = y1, y = x1 - [a / y1 ]         [ ] 是去尾取整
因此,可以在求gcd(a,b) 的同时,对 ax + by = gcd(a,b) 求解。
实现代码:

int GcdEx(int x, int y, int a, int b)
{
	if (b == 0)
	{
		x = 1;
		y = 0;//不知道为啥 
		return a;
	}
	int x1, y1;
	int gcd = GcdEx(b, a % b, x1, y1);
	x = y1;
	y = x1 - a / b * y1;
	return gcd;
}

ax + by = c 有整数解的充要条件是gcd(a, b) | c
设 d = gcd(a,b), k = c / d,ax + by = d 的解是 x1,y1,则 ax + by = c 解集是:
x = k * x1 + t * (b / d)
y = k * y1 - t * (a / d)

  1. 扩展欧几里得算法求 ax ≡ c(mod b)
    ① 求 ax ≡ c(mod b) 等价于求 ax + by = c
    设 d = gcd(a, b), k = c / d,ax + by = d 的解是x1, y1。
    故 ax≡c (mod b) 的解集是:
    x = k * x1 + t * (b / d),t 为任意整数
    其中模 b 不同的解共有 d 个,为:
    x = k * x1 + t * (b / d) ,t = 0,1,…d-1
    ② 求 ax c(mod b) 的最小非负 整数解:
    令 ans = k,s = b / d;
    则 x = ans + t * s,t 为任意整数
    则最小非负整数解是:
    (ans % s + s) % s
    ③ 例题:对下面的循环:
    for (variable = A; variable != B; variable += C)
    statement;
    A,B,C和 variable 都是 K(K<=32) 比特的无符号数 运算的结果也是 K 比特的无符号数,给定 A,B,C 和 K ,问循环执行多少次。
    分析:实际上就是求 A + CX B (mod 2 K ) 的最小非负整数解
               CX ≡(B A) (mod 2 K )
  2. 线性筛法求素数

朴素筛法求 n 以内的所有质数:

  • 初始时容器内为 2 到 n 的所有数
  • 取出最小的数 p,p 一定是质数 删去除 p 外的所有 p 的倍数
  • 重复上述步骤直到向后找不到没被删掉的数

缺陷:一个数可能被重复删去多次,影响效率
改进:对每个素数 p 考虑所有 i , 若 p 小于等于 i 的最小素因子则将 i * p 去掉
实现代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() 
{
	int n; 
	cin >> n; //求 n 以内素数
	vector<int> prime; 
	vector<bool> isPrime(n + 1, true);
	for (int i = 2; i <= n; i++)
	{
		if (isPrime[i])
		{
			prime.push_back(i);//处理到 i 时它还没被删掉,则 i 为素数
		}
		for (int j = 0; j < prime.size(); j++)
		{
			//prime[j]是 i 的最小素因子 
			if (i * prime[j] <= n)
			{
				isPrime[i * prime[j]] = false;
			} 
			else
			{
				break;
			}
			if (i % prime[j] == 0)
			{
				break;
			}
		}
	}
	for (int i = 0; i < prime.size(); i++)
	{
		cout << prime[i] << endl;
	}
	return 0;
}
  1. 欧拉函数、欧拉定理和费马小定理
    欧拉函数
    ① 欧拉函数φ(n) = 小于 n 且和 n 互质的正整数 (包括 1) 的个数(n 为正整数);
    ② 完全余数集合:Zn = { 小于 n 且和 n 互质的数 }   |Zn| = φ( n);
    ③ 对于素数 p,φ( p) = p -1。
    欧拉定理
    互质的正整数 a 和 n ,有 a ^ φ( n)≡ 1 mod n
    费马小定理
    若正整数
    a 与素数 p 互质,则有 a ^ (p - 1) ≡ 1 mod p
    欧拉函数的公式
    (1) 若 p 为素数,正整数 n = p ^ k ,则φ(n) = p^k - p^(k - 1)
    (2) p,q 是两个互质的正整数, n = pq 则 φ(n) = φ( p)φ(q)
    (3) 当 b 是质数,a%b = 0 ,则φ(ab) = φ(a)b
    (4) 对任意 n: φ(n) = n(1 - 1/p1 )(1 - 1/p2 )…(1 - 1/pn),n = p1^a1 * p2^a2 … pn^an (pi 为素数)
    (5) 递推式质数 p 满足 p | x, 若 p^2 | x,则 φ( p) = φ (x/p) * p若 p^2 | x 不成立,则 φ( p) = φ(x / p)*(p - 1)

下面代码实现递推式求欧拉函数:

int euler(int n)
{
	int ret = 1;
	for (int i = 2; i * i < n; i++)
	{
		if (n % i == 0)
		{
			n /= i, ret *= i - 1;
			while (n % i == 0)
			{
				n /= i, ret *= i;
			}
		}
	}	
	if (n > 1)
	{
		ret *= n - 1;
	}
	return ret;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值