首页 > 其他分享 >数论总结

数论总结

时间:2024-08-19 14:15:35浏览次数:12  
标签:总结 pmod 数论 varphi int 逆元 MAXN equiv

数学是毒瘤


基础数论总结。

数论题的代码都是一个个板子拼起来的,本博客只放板子。

声明:本博客中出现的所有代码,都视为加入了 #define int long long

数论题的特点

  1. 题目大意简洁易懂。但有的题还是会古舟一堆

  2. 码量小,全是板子

  3. 极其难想,需要手推公式

  4. long long 是标配


筛法

筛法可以储存所有的质数,也可以 \(O(1)\) 判断质数。

埃氏筛法

时间复杂度 \(O(N\log\log N)\)。

vector<int> pri;
bool is_prime[MAXN];

void primes(int n) {
	for (int i = 2; i <= n; i++) {
		if (is_prime[i]) continue;
		pri.push_back(i);
		for (int j = i; j <= n / i; j++) is_prime[i * j] = 1;
	}
}

线性筛法

线性筛法,也称欧拉筛法,时间复杂度 \(O(N)\)。

vector<int> pri;
bool is_prime[MAXN];

void primes(int n) {
	for (auto &x : is_prime) x = 1;
	for (int i = 2; i <= n; i++) {
		if (is_prime[i]) pri.push_back(i);
		for (auto j : pri) {
			if (i * j > n) break;
			is_prime[i * j] = 0;
			if (i % j == 0) break;
		}
	}
}

分解质因数

任何一个大于 \(1\) 的正整数 \(N\) 都能唯一分解为有限个质数的乘积,可写作:\(N=p_1^{c_1}p_2^{c_2}\cdots p_m^{c_m}\)。

其中 \(c_i\) 都是正整数,\(p_i\) 都是质数,且满足 \(p_1<p_2<\cdots<p_m\)。

算术基本定理的推论

\(N\) 的正约数个数为:

\[(c_1+1)(c_2+1)\cdots(c_m+1)=\prod_{i=1}^m\left(c_i+1\right) \]

\(N\) 的所有正约数的和为:

\[(1+p_1+p_1^2+\cdots+p_1^{c_1})\cdots(1+p_m+p_m^2+\cdots p_m^{c_m})=\prod_{i=1}^m\left(\sum_{j=0}^{c_i}p_i^j\right) \]

试除法分解质因数

int m, p[MAXN], c[MAXN];

void divide(int n) {
	m = 0;
	for (int i = 2; i * i <= n; i++)
		if (n % i == 0) {
			p[++m] = i, c[m] = 0;
			while (n % i == 0) {
				n /= i;
				c[m]++;
			}
		}
	if (n > 1) p[++m] = n, c[m] = 1;
}

最大公约数

欧几里得算法

即辗转相除法,时间复杂度 \(O(\log N)\)。

inline int gcd(int a, int b) {
	if (b == 0) return a;
	return gcd(b, a % b);
}

欧拉函数

定义

定义 \(\varphi(n)\) 表示的是小于等于 \(n\) 和 \(n\) 互质的数的个数。

例如 \(\varphi(1)=1\)。

当 \(n\) 是质数的时候,显然有 \(\varphi(n) = n - 1\)。

2024/7/11 upd. 欧拉函数的公式如下:(其中 \(p_{1\dots m}\) 为 \(x\) 的所有质因数)

\[\varphi(n)=n\times\prod_{i=1}^m\left(1-\frac1{p_i}\right) \]

单个数求欧拉函数

inline int euler_phi(int x) {
	int res = x;
	for (int i = 2; i * i <= x; i++)
		if (x % i == 0) {
			res = res / i * (i - 1);
			while (x % i == 0) x /= i;
		}
	if (x > 1) res = res / x * (x - 1);
	return res;
}

筛法求欧拉函数

利用线性筛法可以快速求出多个数的欧拉函数值。

constexpr int MAXN = 5e6 + 5;
vector<int> prime;
int phi[MAXN];

void euler(int n) {
	phi[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!phi[i]) {
			prime.push_back(i);
			phi[i] = i - 1;
		}
		for (auto j : prime) {
			if (i * j > n) break;
			if (i % j != 0)
				phi[i * j] = phi[i] * phi[j];
			else {
				phi[i * j] = phi[i] * j;
				break;
			}
		}
	}
}

扩展欧拉定理

欧拉定理

若正整数 \(a,n\) 互质,则 \(a^{\varphi(n)}\equiv 1\pmod{n}\)。

欧拉定理的推论

若正整数 \(a,n\) 互质,则对于任意正整数 \(b\),有 \(a^b\equiv a^{b\bmod\varphi(n)}\pmod{n}\)。

当 \(a,n\) 不一定互质且 \(b>\varphi(n)\) 时,有 \(a^b\equiv a^{(b\bmod\varphi(n))+\varphi(n)}\pmod{n}\)。

扩展欧拉定理可用于解决大整数乘方取模问题。

扩展欧几里得

裴蜀定理

对于任意整数 \(a,b\),存在一对整数 \(x,y\),满足 \(ax+by=\gcd(a,b)\)。

扩展欧几里得算法可以在求得 \(\gcd(a,b)\) 的前提下,求解形如 \(ax+by=\gcd(a,b)\) 的方程的解。

由于形如 \(ax\equiv b\pmod p\) 的线性同余方程可以改写为 \(ax+pk=b\) 的形式,所以线性同余方程也可用扩展欧几里得求解。当然,由裴蜀定理,有整数解的充要条件为 \(\boldsymbol{\gcd(a,p)\mid b}\)。线性同余方程也可用逆元求解。计算 \(a\) 的逆元,然后两边同除以 \(a\) 的逆元可得到一个解。

扩展欧几里得算法同样可以求单个数的乘法逆元。

int exgcd(int a, int b, int &x, int &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int res = exgcd(b, a % b, x, y);
	int t = x;
	x = y;
	y = t - a / b * y;
	return res;
}

乘法逆元

费马小定理

若 \(p\) 是质数且 \(a,p\) 互质,则 \(a^{p-1}\equiv 1\pmod{p}\)。

另一个形式:对于任意整数 \(a\),有 \(a^p\equiv a\pmod{p}\)。

定义

如果一个线性同余方程 \(ax \equiv 1 \pmod b\),则 \(x\) 称为 \(a \bmod b\) 的逆元,记作 \(a^{-1}\pmod{b}\)。其实就是倒数

若 \(\boldsymbol b\) 是质数且 \(\boldsymbol{a<b}\),由费马小定理,易得 \(\boldsymbol{a^{b-2}}\) 即为乘法逆元。

如果只是保证 \(a,b\) 互质,则我们可以通过求解同余方程 \(ax\equiv 1\pmod b\) 得到乘法逆元。

扩展欧几里得求单个数的乘法逆元

参见上文,不再赘述。

费马小定理求逆元

参见上文,代码如下:

inv[0] = 1;
for (int i = 1; i < MAXN; i++) inv[i] = power(i, MOD - 2, MOD);

时间复杂度 \(O(N\log N)\),可以在数据规模不大于 \(10^6\) 时求出逆元。

线性求逆元

P3811 乘法逆元

求 \(1\dots n\) 中所有整数在模 \(p\) 意义下的乘法逆元。

\(1\le n\le 3\times 10^6\),\(n<p<20000528\),保证 \(p\) 为质数。

#include <bits/stdc++.h>
#define int long long
using namespace std;

constexpr int MAXN = 3e6 + 5;
int n, p, inv[MAXN];

signed main() {
	cin >> n >> p;
	inv[1] = 1;
	for (int i = 2; i <= n; i++) inv[i] = (p - p / i) * inv[p % i] % p;
	for (int i = 1; i <= n; i++) cout << inv[i] << '\n';
	
	return 0;
}

中国剩余定理

引入

「物不知数」问题:有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二。问物几何?

定义

中国剩余定理 (Chinese Remainder Theorem, CRT) 可求解如下形式的一元线性同余方程组(其中 \(n_1, n_2, \cdots, n_k\) 两两互质):

\[\begin{cases} x &\equiv a_1 \pmod {n_1} \\ x &\equiv a_2 \pmod {n_2} \\ &\vdots \\ x &\equiv a_k \pmod {n_k} \\ \end{cases} \]

上面的「物不知数」问题就是一元线性同余方程组的一个实例。

过程

  1. 计算所有模数的积 \(n\);
  2. 对于第 \(i\) 个方程:
    • 计算 \(m_i=n/n_i\);
    • 计算 \(m_i\) 在模 \(n_i\) 意义下的逆元 \(m_i^{-1}\);
    • 计算 \(c_i=m_im_i^{-1}\)(不要对 \(\boldsymbol{n_i}\) 取模)
  3. 方程组在模 \(n\) 意义下的唯一解为:\(x=\sum_{i=1}^k a_ic_i \pmod n\)。

实现

int crt(int k, int r[], int a[]) {
	int n = 1, ans = 0;
	for (int i = 1; i <= k; i++) n *= r[i];
	for (int i = 1; i <= k; i++) {
		int m = n / r[i], b, y;
		exgcd(m, r[i], b, y);
		ans = (ans + a[i] * m * b % n) % n;
	}
	return (ans % n + n) % n;
}

标签:总结,pmod,数论,varphi,int,逆元,MAXN,equiv
From: https://www.cnblogs.com/laoshan-plus/p/18367209

相关文章

  • HW行动之蓝军总结参考
    HW行动,攻击方的专业性越来越高,ATT&CK攻击手段覆盖率也越来越高,这对于防守方提出了更高的要求,HW行动对甲方是一个双刃剑,既极大地推动了公司的信息安全重视度和投入力量,但同时对甲方人员的素质要求有了很大提升,被攻破,轻则批评通报,重则岗位不保;大的金融、央企可能不担心,有很强的防护,......
  • 【数论】数论分块
    2024-18-19·最后更新时间:2024-18-19\(\Large\mathcal{1,solution(1)}\)如果我们把数\(n\)与小于等于\(n\)的数\(i\)的对应关系打印在表格上会是这样。\(i\)12345678910\(\Large\lfloor\frac{n}{i}\rfloor\)10532211111可以发现\(\Lar......
  • jdk8的Steam流工作常用方法总结
    Steam流工作常用方法总结收集list以某几个字段为键以内容为list的mapMap<String,List<TVoucherDetail>>tVoucherDetailMap=list.stream().collect(Collectors.groupingBy(obj->obj.getDocumentNumber()+"-"+obj.getCertificationData()......
  • JS逆向总结
    总结在进行JS逆向中常用的手段1)Object.defineProperty:对于对象属性的监控 该方法是es5的方法(千万不要以为是es6的哦),作用是直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。(切记只能用在对象身上不能用在数组身上)1、语法 代码解读Obj......
  • 总结指针数组与数组指针的区别
    1、指针数组1-1、定义指针数组是一个数组,其元素是指针。这意味着数组的每个位置都存储了一个指针,这些指针可以指向任何类型的数据(包括其他数组、结构体等)。1-2、类型如果有一个指向整数的指针数组,其类型可能是 int*arr[N];,这里 arr 是一个数组,包含 N 个 int* 类型......
  • C++ 各种初始化方法总结
    在各种编程语言中,初始化都是非常重要的步骤,用于确保对象在使用前具有确定的初始状态。C++提供了多种初始化方法,每种方法都有其特定的使用场景和注意事项。以下是一些主要的初始化方法及其注意事项:默认初始化(Default-initialization):形如Tobj、newT等方式的初始化,其中T为类......
  • java打印流,commons-io工具包,IO总结
    一.打印流1.概述:平时我们在控制台打印输出,是调用print()方法和println()方法完成的,这两个方法都来自于java.io.PrintStream类作用:该类能够方便地打印各种数据类型的值,写入数据后可以实现自动换行。通常用于日志记录2打印流的构造方法publicPrintStream(StringfileName)......
  • 动态规划 总结
    DAG上的动态规划与树形DP这两个词看上去很高大上,但实则就是记忆化搜索,而记忆化搜索其实就是DP的本质。当选择一个需要用全局变量来参与描述状态的方式时,就只能用常规搜索。但当状态可以完全被几个非全局参数确定性的描述时,就可以用记忆化搜索,记忆化搜索可以通过存储答案并直接提取......
  • Hadoop 第六周总结
    在Hadoop学习的第六周,你可能会收获以下关键知识点:YARN(YetAnotherResourceNegotiator):YARN是Hadoop的资源管理和作业调度系统。本周你可能深入了解了YARN的架构及其组件,包括ResourceManager和NodeManager。ResourceManager负责全局资源调度和作业调度,而NodeManag......
  • 2024.8.18 周总结(上周天到这周六集训,这周天放假)
    感觉这一周上难度了,尤其没听懂的是二分图和博弈论那天上午休息完之后的部分。有复习,有新知识,收获还是比较大的。晚上打游戏打多了。文化课没学多少。中午看番、玩寝室楼下桌上的游戏去了,因为寝室要关灯拉窗帘睡得也更早,一周就只写了一点点字帖,看了一点点《乡土中国》。综......