数学知识--数论
目录
质数
素数定理:小于n的正整数大约有
试除法判断素数
点击查看代码
bool is_prime(int x) { for(int i = 2; i <= x / i; i ++) if(x % i == 0) return false; return true; }
分解质因数
点击查看代码
void getdiv(int x) { for(int i = 2; i <= x / i; i ++) { if(x % i == 0) { int s = 0; while(x % i == 0) s ++, x /= i; cout << i << ' ' << s << '\n'; } } if(x > 1) cout << x << ' ' << 1 << '\n'; }
素数筛
1. 诶氏筛法
点击查看代码
void init_prime(int n) { for(int i = 2; i <= n; i ++) if(!st[i]) { prime[cnt ++] = i; for(int j = i * i; j <= n; j += i) st[j] = true; } }
线性筛
点击查看代码
void init_prime(int n) { for(int i = 2; i <= n; i ++) { if(!st[i]) prime[cnt ++] = i; for(int j = 0; prime[j] <= n / i; j ++) { st[i * prime[j]] = true; if(i % prime[j] == 0) break; } } }
约数
唯一分解定理:任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积:
应用
1. 约数个数
若一个正整数
点击查看代码
void S1(int x) { unordered_map<int,int> hash; for(int i = 2; i <= x / i; i ++) while(x % i == 0) x /= i, hash[i] ++; if(x > 1) hash[x] ++; for(auto i:hash) ans = ans * (i.second + 1) % mod; cout << ans << '\n'; }
2. 约数之和
其
点击查看代码
void S2(int x) { unordered_map<int, int> hash; for(int i = 2; i <= x / i; i ++) while(x % i == 0) x /= i, hash[i] ++; if(x > 1) hash[x] ++; int ans = 1; for(auto i : hash) { int a = i.first, b = i.second, t = 1; while(b --) t = (a * t + 1) % mod; ans = ans * t % mod; } cout << ans << '\n'; }
3. 求解
4. 求组合数
在不取
试除法求所有约数
点击查看代码
vector<int> get_x(int x) { vector<int> s; for(int i = 2; i <= x / i; i ++) if(x % i == 0) { s.push_back(i); if(x / i != i) s.push_back(x / i); } return s; }
欧拉函数
欧拉函数:
点击查看代码
int erula(int x) { int ans = x; for(int i = 2; i <= x / i; i ++) if(x % i == 0) { ans = ans / i * (i - 1); while(x % i == 0) x /= i; } if(x > 1) ans = ans / x * (x - 1); return ans; }
筛法求欧拉函数
(1) 质数i的欧拉函数即phi[i]=i−1,1 i−1均与i互质,共i−1个。
(2) phi[primes[j]∗i] 分为两种情况:
点击查看代码
void get_eulers(int n) { phi[1] = 1; for(int i = 2; i <= n; i ++) { if(!st[i]) { primes[cnt ++] = i; phi[i] = i - 1; } for(int j = 0; primes[j] * i <= n; j ++) { st[primes[j] * i] = true; if(i % primes[j] == 0) { phi[primes[j] * i] = phi[i] * primes[j]; break; } phi[primes[j] * i] = phi[i] * (primes[j] - 1); } } }
例 可见的点
题目描述:
在一个平面直角坐标系的第一象限内,如果一个点
例如,点
部分可见点与原点的连线如下图所示:
编写一个程序,计算给定整数
输入格式:
第一行包含整数
每组测试数据占一行,包含一个整数
输出格式:
每组测试数据的输出占据一行。
应包括:测试数据的编号(从 1 开始),该组测试数据对应的
同行数据之间用空格隔开。
输入
4
2
4
5
231
输出
1 2 5
2 4 13
3 5 21
4 231 32549
数据范围
点击查看代码
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long using namespace std; const int N = 1010; int prime[N], phi[N]; bool st[N]; int n, cnt, t, ans; void init() { st[1] = 1; for(int i = 2; i < N; i ++) { if(!st[i]) { prime[cnt ++] = i; phi[i] = i - 1; } for(int j = 0; prime[j] * i <= N; j ++) { st[i * prime[j]] = true; if(i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * (prime[j]); break; } else phi[i * prime[j]] = phi[i] * (prime[j] - 1); } } } void solve() { cin >> n; t ++, ans = 0; for(int i = 1; i <= n; i ++) ans += phi[i] * 2; cout << t << ' ' << n << ' ' << ans + 3 << '\n'; } int main() { IOS; init(); int T = 1; cin >> T; while(T --) solve(); return T ^ T; }
快速幂
数的乘方满足性质:
又因
故可预处理出
令
将
二进制可以表示所有数,且用单一用二进制表示时,b单一表示最大可表示为二进制形式的2logb
点击查看代码
int qmi(int a, int b, int p) { int ans = 1; while(b) { if(b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans; }
快速幂求逆元
**乘法逆元的定义:若整数
裴属定理(贝祖定理):对于任意不全为零的整数
费马小定理:假如
若
又有
故
点击查看代码
int qminv(int a, int p) { int ans = 1, b = p - 2; while(b) { if(b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans; }
矩阵乘法
矩阵的乘积和数的乘积具有类似的幂次性:
可利用矩阵的幂次性结合快速幂加速求解一些有关系的数据
令矩阵
一般关系矩阵由问题给出,系数矩阵要根据关系矩阵的关系推导出来
例1. Fibonacci数列第n项
题目描述:
大家都知道,斐波那契数列是满足如下性质的一个数列:
请你求出
输入格式:
一行一个正整数
输出格式:
输出一行一个整数表示答案。
输入1
5
输出1
5
输入2
10
输出2
55
数据范围
对于 60% 的数据,
;
对于 100% 的数据,。
点击查看代码
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long #define mod1 1000000007 #define mod2 998244353 using namespace std; typedef __int128 i128; const int N = 2; void mul(int c[][N], int b[][N], int a[][N]) { int t[N][N]; memset(t, 0, sizeof t); for(int i = 0; i < N; i ++) for(int j = 0; j < N; j ++) for(int k = 0; k < N; k ++) t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % mod1; memcpy(c, t, sizeof t); } void solve() { int n; cin >> n; n --; int f[N][N] = {1, 1}; int a[N][N] = { {0, 1}, {1, 1} }; while(n) { if(n & 1) mul(f, a, f); mul(a, a, a); n >>= 1; } cout << f[0][0] << '\n'; } signed main() { IOS; int _ = 1; while(_ --) solve(); return _ ^ _; }
例2. Fibonacci前n项和
题目描述:
佳佳对数学,尤其对数列十分感兴趣。
在研究完
例如用
可这对佳佳来说还是小菜一碟。
终于,她找到了一个自己解决不了的问题。
用
现在佳佳告诉你了一个
输入格式:
共一行,包含两个整数
输出格式:
共一行,输出
输入
5 5
输出
1
数据范围与解释
点击查看代码
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long using namespace std; const int N = 4, M = 50; int n, m; void mul(int c[][N], int a[][N], int b[][N]) { static int t[N][N]; memset(t, 0, sizeof t); for(int i = 0; i < N; i ++) for(int j = 0; j < N; j ++) for(int k = 0; k < N; k ++) t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % m; memcpy(c, t, sizeof t); } void solve() { cin >> n >> m; int f1[N][N] = {1, 1, 1, 0}; int a[N][N] = { {0, 1, 0, 0}, {1, 1, 1, 0}, {0, 0, 1, 1}, {0, 0, 0, 1}, }; int k = n - 1; while(k) { if(k & 1) mul(f1, f1, a); mul(a, a, a); k >>= 1; } cout << ((n * f1[0][2] - f1[0][3]) % m + m) % m << '\n'; } signed main() { IOS; int _ = 1; // cin >> _; while(_ --) solve(); return _ ^ _; }
扩展欧几里得
1.扩展欧几里得
用于求解
当
当
而
故
因此可以递归求解
2.一般的同余方程 ax + by = c
可设
求解:
用扩展欧几里得求出
则
故而特解为
而通解 = 特解 + 齐次解
而齐次解即为方程
故而通解为
若令
3.应用:求解一次同余方程 ax ≡ b(mod m)
等价于求解
有解条件为
若
例1. 扩展欧几里得
题目描述:
给定
输入格式:
第一行包含整数
接下来
输出格式:
输出共
本题答案不唯一,输出任意满足条件的
输入
2
4 6
8 18
输出
-1 1
-2 1
数据范围
点击查看代码
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long using namespace std; int exgcd(int a, int b, int &x, int &y) { if(!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } void solve() { int a, b, x, y; cin >> a >> b; int d = exgcd(a, b, x, y); cout << x << ' ' << y << '\n'; } signed main() { IOS; int _ = 1; cin >> _; while(_ --) solve(); return 0; }
例2. 求解同余方程
题目描述:
给定 impossible
。
输入格式:
第一行包含整数
接下来
输出格式:
输出共 impossible
。
每组数据结果占一行,结果可能不唯一,输出任意一个满足条件的结果均可。
输出答案必须在
输入
2
2 3 6
4 3 5
输出
impossible
-3
数据范围
点击查看代码
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long using namespace std; using LL = long long; int n, x, y; int exgcd(int a, int b, int &x, int &y) { if(!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, x, y); int z = x; x = y, y = z - a / b * y; return d; } void solve() { int a, b, m; cin >> a >> b >> m; int d = exgcd(a, m, x, y); if(b % d) cout << "impossible\n"; else { x = (LL) x * b / d % m; cout << x << endl; } } signed main() { IOS; int _; cin >> _; while(_ --) solve(); return _ ^ _; }
例3. 青蛙的约会
题目描述:
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙 A 和青蛙 B,并且规定纬度线上东经 0 度处为原点,由东往西为正方向,单位长度 1 米,这样我们就得到了一条首尾相接的数轴。设青蛙 A 的出发点坐标是 x,青蛙 B 的出发点坐标是 y。青蛙 A 一次能跳 m 米,青蛙 B 一次能跳 n 米,两只青蛙跳一次所花费的时间相同。纬度线总长 L 米。现在要你求出它们跳了几次以后才会碰面。
输入格式:
输入只包括一行五个整数
输出格式:
输出碰面所需要的次数,如果永远不可能碰面则输出一行一个字符串 Impossible
。
输入
1 2 3 4 5
输出
4
数据范围
对于 100% 的数据,
。
点击查看代码
#include<bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long using namespace std; int exgcd(int a, int b, int &x, int &y) { if(!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } void solve() { int a, b, m, n, l; cin >> a >> b >> m >> n >> l; int x, y; int d = exgcd(n - m, l, x, y); if((a - b) % d) cout << "Impossible\n"; else { int s = (a - b) / d * x; int t = abs(l / d); cout << (s % t + t) % t << '\n'; } } signed main() { IOS; int _ = 1; // cin >> n; while(_ --) solve(); return _ ^ _; }
中国哦剩余定理(孙子定理)
则
1. 将式子等价转换
对于每两个式子(考虑将其合并):
则有:
进而:
即:
①
也就是需要找到一个最小的
2. 用扩展欧几里得算法找出一组解
已知
无解判断:
若
设
依上文,只需让k1,k2分别扩大y倍,则可以找到一个k1,k2满足①式:
3. 找到最小正整数解
已知性质:
②
证明:
将新的
裂项,拆负号化简:
这个式子和①是一样的,因 ① 成立,故此式也成立。
要找一个最小的非负整数解,只需让
即可找到当前最小的
因为不知道
4. 等效替代:
由 ② 式带入
新的x为:
这只是前两个式子得最小k,有可能遇到下一个式子后面被迫要扩大
在 ③ 中,设
则:
③
这个形式与一开始分解的形式特别像
假设之后又来了一个
5. 总结
此做法相当于每次考虑合并两个式子,将这n个式子合并
注意:
(1)
(2)
例1. 表达整数的奇怪方式
题目描述:
给定
输入格式:
第
第
输出格式:
输出最小非负整数
如果存在
输入
2
8 7
11 9
输出
31
数据范围
点击查看代码
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long using namespace std; int n; int exgcd(int a, int b, int &x, int &y) { if(!b) { x = 1, y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } int inline mod(int a, int b) { return ((a % b) + b) % b; } void solve() { cin >> n; int a1, m1; cin >> a1 >> m1; for(int i = 1; i < n; i ++) { int a2, m2, k1, k2; cin >> a2 >> m2; int d = exgcd(a1, -a2, k1, k2); if((m2 - m1) % d) { puts("-1"); return ; } k1 = mod(k1 * (m2 - m1) / d, abs(a2 / d)); m1 = k1 * a1 + m1; a1= abs(a1 / d * a2); } cout << m1 << endl; } signed main() { IOS; int _ = 1; // cin >> _; while(_ --) solve(); return _ ^ _; }
例2. 曹冲养猪
题目描述:
自从曹冲搞定了大象以后,曹操就开始琢磨让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲很不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。
举个例子,假如有
你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?
输入格式:
第一行包含一个整数
接下来
你可以假定
输出格式:
输出仅包含一个正整数,即为曹冲至少养猪的数目。
输入
3
3 1
5 1
7 2
输出
16
数据范围
所有的乘积不超过
点击查看代码
#include <bits/stdc++.h> #define IOS ios::sync_with_stdio(false);cin.tie(nullptr),cout.tie(nullptr) #define int long long using namespace std; const int N = 15; int m[N], a[N]; int n; void exgcd(int a, int b, int &x, int &y) { if(!b) x = 1, y = 0; else { exgcd(b, a % b, y, x); y -= a / b * x; } } void solve() { cin >> n; int M = 1; for(int i = 0; i < n; i ++) { cin >> m[i] >> a[i]; M *= m[i]; } int ans = 0; for(int i = 0; i < n; i ++) { int mi = M / m[i]; int ti, y; exgcd(mi, m[i], ti, y); ans += mi * a[i] * ti; } cout << (ans % M + M) % M << endl; } signed main() { IOS; int _ = 1; // cin >> _; while(_ --) solve(); return _ ^ _; }
本文作者:chfychin
本文链接:https://www.cnblogs.com/chfychin/p/17741732.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步