数论学习笔记(一):同余相关
一、最大公约数
定义
不全为
欧几里得算法(gcd)
gcd是用来求解两个整数的最大公约数
定理1.2.1
对于整数
证:
设
定理1.2.2
若
证:设
反过来,设
解法
令整数
正确性证明:通过连续的带余除法可以得到:
根据定理1.2.2,
裴蜀定理
定理1.3.1
对于两个不全为
证:设
假设
内容
裴蜀定理是用来判断一个形如
对于整数
证:若整数
假设
设
令
反过来,假设整数
扩展欧几里得算法(exgcd)
求
现在已知
因此
先一层层递归,回溯时求解原方程的解。
exgcd代码:
int extend_gcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1;
y = 0;//递归边界
return 0;
}
int d = extend_gcd(b, a % b, y, x);//递归
y -= a / b * x;//回溯
return d;
}
二、素数
定义
素数是大于
大于
筛法求素数
下面给出两种可以在线性时间内筛出
埃拉托色尼斯筛法
首先,一个正整数的倍数一定是合数。
如果一个数是合数,那他一定能表示成比他小的数的倍数。
我们考虑用已经筛出的素数的倍数表示合数。
从
这个方法被称作埃拉托色尼斯筛法,简称埃氏筛,复杂度
复杂度证明:设
在
设
记
记
中置知识:下凸函数
如果一个函数
就是一个下凸函数。
设
中置知识:琴生不等式
一般形式:若
加权形式:若
证:(加权形式)
考虑数学归纳法
当
当
不等式成立。
完整代码:P3383 【模板】线性筛素数
#include<bits/stdc++.h>
using namespace std;
const int PP = 1e8 + 9;
int prime[PP], p_cnt;
bool isPrime[PP];
void getPrime(int n){
for(int i = 2; i < n; ++i)
isPrime[i] = true;
for(int i = 2; i < n; ++i){
if(isPrime[i]){//一个数没被标记过
prime[++p_cnt] = i;//记录素数
if(1ll * i * i < n)//防止越界
for(int j = i * i; j <= n; j += i)//根据合数i的最小质因子小于等于sqrt(i),可以从i*i开始筛,优化常数
isPrime[j] = false;//他的倍数标记为合数
}
}
}
signed main(){
int n, q;
scanf("%d%d", &n, &q);
getPrime(n);
while(q--){
int x;
scanf("%d", &x);
printf("%d\n", prime[x]);
}
return 0;
}
欧拉筛法
埃氏筛十分优秀,但每个数会被它的所有质因子都筛一遍,而使用欧拉筛可以使每个数只被它的最小质因子筛一遍,时间复杂度可以达到
每找到一个没被标记的数,就将它记为素数,无论他是不是素数,都将它与已求出的素数相乘并将他标记为合数。
当遇到一个素数能整除当前的数,证明当前的数已经被这个素数标记过了,他乘其它质数也已经被这个质数标记了,就可以退出循环了。
完整代码:P3383 【模板】线性筛素数
#include<bits/stdc++.h>
using namespace std;
const int PP = 1e8 + 9;
int prime[PP], p_cnt;
bool isPrime[PP];
void getPrime(int n){
for(int i = 2; i < n; ++i)
isPrime[i] = true;
for(int i = 2; i < n; ++i){
if(isPrime[i])
prime[++p_cnt] = i;
for(int j = 1; j <= p_cnt && i * prime[j] < n; ++j){
isPrime[i * prime[j]] = false;//将prime[j]的第i倍标记为合数
if(i % prime[j] == 0)//因为prime数组从小到大排列,因此prime[j]一定是i的最小质因子,i乘其它质数一定会被prime[j]先筛掉,因此不用往后再筛了
break;
}
}
}
signed main(){
int n, q;
scanf("%d%d", &n, &q);
getPrime(n);
while(q--){
int x;
scanf("%d", &x);
printf("%d\n", prime[x]);
}
return 0;
}
欧拉函数
有数学的地方就有欧拉——《公式之美》
前置知识:积性函数
若对于任意正整数
若对于任意正整数
定义
欧拉函数
欧拉函数的性质
1.若
证:若
反过来,如果
2.对于素数
证:不超过
3.(积性函数) 对于任意正整数
证:用下列方式列出不超过
假设
4.(通项公式) 设
证:根据性质3,
根据性质2,
5.(欧拉反演) 若
证:将
现在我们将
因为
6.若
证:
线性筛欧拉函数
首先,对于一个素数
利用欧拉筛
-
如果
,根据性质6,有 -
如果
,因为 为素数,因此 ,根据性质3,有
线筛代码:
const int N = 4e6 + 9;
int vis[N], prime[N], phi[N], sum[N], n;
void get_phi(){
phi[1] = 1;
int cnt = 0;
for(int i = 2; i < N; i++){
if(!vis[i]){
vis[i] = i;
prime[cnt++] = i;
phi[i] = i - 1;//素数
}
for(int j = 0; j < cnt; j++){
if(i * prime[j] > N)
break;
vis[i * prime[j]] = prime[j];
if(i % prime[j] == 0){
phi[i * prime[j]] = phi[i] * prime[j];//非素数情况1
break;
}
phi[i * prime[j]] = phi[i] * phi[prime[j]];//非素数情况2
}
}
}
三、同余
定义
对于整数
同余的性质
1.自反性:
证:
2.对称性:若
证:
设
3.传递性:若
证:
设
4.可加性:若 自然两边同时减也是可以的)
证:
设
5.可乘性:若
证:
设
6.可除性:若
可除性前置一:若
证:
设
可除性前置二:若
证:
两边同乘
根据可除性前置一,
证:
设
可除性推论:若
费马小定理
内容
对于质数
费马小定理也通常被写作
证明
证明:考虑数学归纳法
首先 (显然成立)
假设对于正整数
符合数学归纳法,等式成立。
逆元
定义
由可除性可知,模意义下的除法受
这是我们可以将除
形式化的,若
费马小定理求逆元
模板:
#include <bits/stdc++.h>
using namespace std;
int qpow(int x, int p, int m){
int res = 1;
while(p > 0){
if (p % 2 == 1)
res = res * x % m;
p /= 2;
x = x * x % m;
}
return res;
}
int n, p;
int main(){
scanf("%d%d", &n, &p);
printf("%d", qpow(n, p - 2, p));
return 0;
}
扩展欧几里得算法求逆元
设
移项得:
模板:
#include <bits/stdc++.h>
using namespace std;
int extend_gcd(int a, int b, int &x, int &y){
if(b == 0){
x = 1;
y = 0;
return 0;
}
int d = extend_gcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int mod_inverse(int a, int m){
int x, y;
extend_gcd(a, m, x, y);
return (x % m + m) % m;
}
int n, p;
int main(){
scanf("%d%d", &n, &p);
printf("%d", mod_inverse(n, p));
return 0;
}
递推求逆元
当我们要求
首先,
对于
两边同乘
带入
#include <bits/stdc++.h>
using namespace std;
const int N = 3e6 + 9;
int inv[N], n, p;
int main(){
scanf("%d%d", &n, &p);
inv[1] = 1;
printf("1\n");
for(int i = 2; i <= n; i++){
inv[i] = (p - p / i) * inv[p % i] % p;
printf("%d\n", inv[i]);
}
return 0;
}
欧拉定理(扩展费马小定理)
内容
对于正整数
证明
证:我们知道,
把每个数乘
假设
假设
假设不成立
威尔逊定理
内容
若
定理3.5.1
对于整数
证:
设
移项得:
整数
其中
设两个解
这表明
推论:对于整数
定理3.5.2
对于素数
证:若
反过来,若
证明
证:当
当
根据定理3.5.2可得,在小于
将同余式两边同乘
威尔逊定理逆定理
内容
对于正整数
定理3.5.3
对于整数
证:
设
证明
假设
假设
中国剩余定理
内容
中国剩余定理是用来求解以下方程:(
定理3.6.1
对于整数
证:
解法
解:令
可以发现此时
通解
四、原根
前置知识:阶
定义
对于整数
阶的性质
1.对于整数
证:若
反过来,若
2.对于整数
证:若
反过来,若
原根
定义
对于整数
定理4.2.1
对于整数
证:
原根的存在性
1.设
证:设
原根的存在性1推论:每个素数都有原根
2(扩展).如果正整数
证:设
设
定理4.2.2
对于正整数
证:设
定理4.2.2推论:若
定理4.2.3
对于正整数
证:
假设有
原根的个数
对于正整数
证:
定理4.2.4(拉格朗日定理)
假设
证:考虑数学归纳法。
当
当
设
定理4.2.5
对于素数
证:设
原根的应用
观察定理4.2.5的式子,它的形式和单位根完全一样。
由于形如
参考资料
-
A Friendly Introduction to Number Theory(Fourth edition) Joseph H. Silverman
-
Elementary Number Theory and Its Application(Sixth Edition) Kenneth H. Rosen
-
初等数论学习笔记 I:同余相关 Alex_wei
-
初等数论学习笔记 III:数论函数与筛法 Alex_wei
-
琴生不等式 百度百科
-
筛法 OI Wiki
本文来自博客园,作者:JPGOJCZX,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18422811
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效