花开不是为了花落,而是为了更|

wnsyou

园龄:2年4个月粉丝:19关注:16

2023-05-04 20:40阅读: 40评论: 0推荐: 0

数学与数论

数论和数学都好难/kk

白皮书第 6 章,进阶指南 0x03。

0xFF 一些链接

【数学2-1】进阶数论 | 《算法竞赛进阶指南》第四章—数学知识 | OI-wiki-数学

0x00 取模

模运算,常用于大数计算,当答案数值非常大时,通常会有两种情况,第一种是取模,通过模上一个较小的数来方便输出和计算;还有一种是高精度,有这个的题目就会比较恶心。

取模有以下性质:

  1. 可加性:(a + b) mod m = ((a mod m) + (b mod m)) mod m
  2. 可减性:(a - b) mod m = ((a mod m) - (b mod m)) mod m,c++实现时为了避免出现负数,通常要在括号中加上模数 m
  3. 可乘性:(a×b) mod m = ((a mod m)×(b mod m)) mod m
  4. 没有可除性!除法取模等于乘除数的逆元。

0x01 乘法取模

两数直接乘,可能导致爆 long long 导致寄掉(噢当然你可以用 __int128,数据实在太大则考虑是否需要使用高精度),这里给出一个不一定在所有情况下都有用的解决办法。

原理:x×y 会爆,可以考虑变成 (x×2)×(y / 2),然后变成 (x×22)×(y / 22),以此类推,直到 y=0,详细证明见白皮书第 389 页。

如果 x 还是不幸爆炸了,那么就需要考虑高精度,但这个做法基本上可以规避掉大部分情况。

using ll = long long;
ll mul (ll x, ll y, ll mod) { // (x * y) % mod
x %= mod, y %= mod; // 首先规避一下
ll res = 0;
while (y) {
if (y & 1) { // 判断奇偶性
res = (res + x) % mod;
}
x = x * 2 % mod, y >>= 1;
}
return res;
}

0x10 快速幂

OI-wiki-快速幂

计算 xnmodm,朴素算法当然是一个个数去乘,边乘边取模,时间复杂度 O(n),十分不优秀。

一种做法是分治法,看白皮书去。

另一种就是位运算,时间复杂度 O(logn),十分优秀,是标准的做法。


举个例子,求 a11 = ?,朴素算法当然能做,但肯定不会去讲。

a11 分解成 a8×a2×a,每个数的幂次都是 2 的倍数。 那么就可以方便地计算了。

求幂次,用二进制分解,11=(1011)2,跳过 a4 即可。

具体实现看代码。

using ll = long long;
ll qmod (ll x, ll y, ll mod) { // x ^ y % mod
ll sum = 1;
while (y) {
if (y % 2) {
sum = (sum * x) % mod;
}
y >>= 2, x = (x * x) % mod;
}
return sum;
}

0x20 gcd 和 lcm

OI-wiki-最大公约数

最大公约数和最小公倍数研究整除等问题,也可以用在概率问题的分数通分等等。


备注:

  • 最大公约数,Greatest Common Divisor(GCD)Greatest Common Denominator(GCD)Greatest Common Factor(GCF)Highest Common Factor(HCF)
  • 最小公倍数,Least Common Multiple(LCM)

0x21 GCD

整数 ab 的最大公约数,就是一个最大的整数 ccacb,记作 gcd(a,b)

注意,因为是最大公约数,而 |a| 又是 a 的约数(a 无论是负数或非负数),所以对于任意的 (a,b),有 gcd(a,b)=gcd(|a|,|b|)

GCD有以下性质:

  1. gcd(a,b)=gcd(a,k×a+b)
  2. gcd(k×a,k×b)=k×gcd(a,b)
  3. 多个整数的 GCD:gcd(a,b,c,d)=gcd(gcd(a,b),gcd(c,d)),即 GCD 具有交换律和结合律(可以这么叫吧,理解万岁)
  4. gcd(a,b)=d,则 gcd(ad,bd)=1,即 adbd 互质
  5. gcd(a+c×b,b)=gcd(a,b)

代码有几种,当然你也可以使用自带的函数 __gcd(a, b),但要确保 a0b0

1st欧几里得算法

辗转相除法,是最常用的写法,唯一的缺点就是取模常数太大了,复杂度参考白皮书。

int gcd (int x, int y) {
return (y ? gcd(y, x % y) : x);
}

极简版

int gcd (int a, int b) {
while (a ^= b ^= a ^= b %= a) {
}
return b;
}

2nd 更相减损术

基于性质:gcd(a,b)=gcd(b,ab)=gcd(a,ab)

计算步骤:gcd(a,b)={aa=bgcd(ab,b)a>bgcd(a,ba)a<b

int gcd (int x, int y) {
while (x != y) {
if (x > y) {
x -= y;
} else {
y -= x;
}
}
return x;
}

更相减损术虽然避免了取模的常数,但在最极端的情况下时间复杂度可以达到 O(max(a,b)),实在不够优秀。在求 gcd(109,1) 时就会爆炸。

3rd Stein 算法

基于更相减损术,对于一些情况进行讨论和优化,具体如下:

  • ab 同为偶数,gcd(a,b)=2×gcd(a2,b2)
  • ab 同为奇数,gcd(a,b)=gcd(a+b2,ab2)
  • ab 偶,根据性质 2 可得 gcd(a,b)=gcd(a2,b)
  • ab 奇,根据性质 2 可得 gcd(a,b)=gcd(a,b2)

结束条件仍然是 a=b 时返回 a

using ll = long long;
ll gcd (ll a, ll b) {
if (a < b) {
return gcd(b, a);
} else if (a == b) {
return a;
}
if (a % 2 == b % 2) {
return (a % 2 == 0 ? 2 * gcd(a / 2, b / 2) : gcd((a + b) / 2, (a - b) / 2));
}
return (a % 2 == 0 ? gcd(a / 2, b) : gcd(a, b / 2));
}

0x22 LCM

有 LCM,必有 GCD!!!1      ——鲁迅

OI-wiki-最小公倍数

推论自己看白皮书,结论就是 lcm(a,b) = a×b / gcd(a,b)

为了防止爆炸,可以先除再乘。

int lcm (int x, int y) {
return 1ll * x / gcd(x, y) * y;
}

0x23 裴蜀定理

OI-wiki-裴蜀定理

又名贝祖定理(Bézout's lemma),是关于 GCD 的一个定理。

  • 初步定理:若有一个整数二元组 (x, y),则必然存在一个整数二元组 (a, b) 使得 a×x+b×y=gcd(x,y),这个等式被称为 Bézout 等式。
  • 推论:整数 ab 互质当且仅当存在整数 xy 使得 a×x+b×y=1

0x30 扩展欧几里得算法

OI-wiki-扩展欧几里得算法

洛谷大佬的 tj 也还挺详细的

简称扩欧(Extended Euclidean algorithm, EXGCD),常用于求 ax+by=c 的一组特解,过程自己看OI-wiki或白皮书,代码:

int exgcd (int a, int b, ll &x, ll &y) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, x, y);
swap(x, y), y -= x * (a / b);
return d;
}

0x40 同余

OI-wiki-线性同余方程

同余是数论的一个基本理论,是很巧妙的工具,它使人们能够用等式的形式简洁地描述整除关系。相关内容有欧拉定理、费马小定理、扩欧、乘法逆元、线性同余方程、中国剩余定理等等。

0x41 同余的定义

  • 同余的定义:设 m 为正整数,ab 都为整数,若 m(ab),则称 abm 同余。
    • 记作 ab(modm)
    • 同样也不用考虑 ab 的正负,其实就是要带个绝对值。
  • 剩余系:一个模 m 完全剩余系是一个整数的集合,使得每个整数都与此集合中的一个整数模 m 同余,例如 [0,1,2m1] 就是模 m 完全剩余系,称为模 m 最小非负剩余的集合,剩余系在线性同余方程中有应用。

0x42 同余的定理及性质

首先,a,b,c,d,m 均为整数。

ab(modm) 当且仅当 amodm=bmodm

把同余式转成等式,即 a=b+kmk 为整数,这说明了同余方程与线性丢番图方程的关系。

m 为正整数,则模 m 有以下性质:

  1. 自反性:aa(modm)
  2. 对称性:若 ab(modm),则 ba(modm)
  3. 传递性:若 ab(modm)bc(modm),则 ac(modm)

同余具有可加可减可乘可乘方性,若 ab(modm)cd(modm),则:

  1. 可加性:a+cb+c(modm),甚至 a+cb+d(modm)
  2. 可减性:acbc(modm),甚至 acbd(modm)
  3. 可乘性:acbc(modm),甚至 acbd(modm)
  4. 同样不存在可除性,除法取模需要逆元。
  5. 同余的幂(可乘方性):对于任意正整数 kakbk(modm)

0x43 一元线性同余方程

一元线性同余方程,即给定 a,b,m,求整数 x 满足:axb(modm)

研究这个有啥用?axb(modm) 表示 axbm 的倍数,设为 y 倍,则有 ax+my=b,这就是二元线性丢番图方程。。。(胡言乱语)

0x44 乘法逆元

模板题:P3811 【模板】模意义下的乘法逆元

乘法逆元主要有三种求法:扩欧、费马小定理、递推预处理。

扩欧

P1082 [NOIP2012 提高组] 同余方程

  • 优点:可以求出 m 不为质数时的同余方程解。

  • 缺点:和费马小定理差不多。

ax1(modm),转为 ax+bm=1,先求出特解 x0,则通解为 x=x0+mn,最小整数解就是 ((x0modm)+m)modm

#include <iostream>
using namespace std;
using ll = long long;
ll x, y, z, w;
void exgcd (ll x, ll y, ll &z, ll &w) {
if (!y) {
z = 1, w = 0;
return ;
}
exgcd(y, x % y, w, z), w -= x / y * z;
}
int main () {
ios::sync_with_stdio(0), cin.tie(0);
cin >> x >> y;
exgcd(x, y, z, w);
cout << (z % y + y) % y;
return 0;
}

费马小定理

  • 优点:复杂度为 O(logm),处理较少元素逆元十分迅速。

  • 缺点:当元素个数来到更高数量级时就不行了,或者 m 不为质数。

费马小定理,大致就是说 xm11(modm),那么可以推出 1xxm2(modm)

用快速幂处理即可。

递推预处理

  • 优点:当需要处理元素在一个 O(n) 能够处理的范围内时,可以快速求出它们的逆元。

  • 缺点:当元素很大时无能为力,或者 m 不为质数。

证明自己翻书,代码如下:

const int N = 1e5 + 10;
int inv[N];
inv[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = 1ll * (m - m / i) * inv[m % i] % m;
}

0x60 欧拉函数

欧拉函数(Euler's totient function),即 φ(n)=1in(gcd(i,n)=1),当 n 为质数时明显有 φ(n)=n1

0x61 性质

  1. 欧拉函数是积性函数,即当 gcd(a,b)=1 时,φ(a×b)=φ(a)×φ(b)
  2. n=1in&inφ(i),详细证明见 OI-wiki
  3. 详细见 OI-wiki。

0x62 欧拉定理

有个正整数 m,和一个整数 a,若 gcd(a,m)=1,则有 aφ(m)1(modm)

0x63 求 1n 的欧拉函数值

可以在进行欧拉筛的同时计算出每个数的欧拉函数值。

// pri 记录的是质数,phi 记录的是欧拉函数值
f[1] = 1;
for (int i = 2; i <= n; i++) {
if (!f[i]) {
pri[++cnt] = i, phi[i] = i - 1;
}
for (int j = 1; j <= cnt && i * pri[j] <= n; j++) {
f[pri[j] * i] = 1, phi[pri[j] * i] = phi[i] * (pri[j] - bool(i % pri[j]));
if (i % pri[j] == 0) {
break;
}
}
}

0xE0 随手记

0xE1

给出四条边,如何判断是否能够组成梯形。

换句话说,就是梯形的四条边之间有什么关系。

结论:两腰和 > 两底差,两腰差 < 两底差

0xE2 海伦公式

百度百科链接

简单来说,就是给出三角形三边长度 abc,求三角形面积的一个公式。

p=a+b+c2,那么三角形面积就是 p×(pa)×(pb)×(pc)

0xE3 Cab

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, mod = 1e9 + 7;
int n, inv[N], x[N], f[N], a, b;
int C (int a, int b) {
return 1ll * f[a] * x[b] % mod * x[a - b] % mod;
}
int main () {
ios::sync_with_stdio(0), cin.tie(0);
inv[1] = x[0] = f[0] = 1;
for (int i = 2; i <= 2e5; i++) {
inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
}
for (int i = 1; i <= 2e5; i++) {
x[i] = 1ll * x[i - 1] * inv[i] % mod, f[i] = 1ll * f[i - 1] * i % mod;
}
return 0;
}

本文作者:wnsyou

本文链接:https://www.cnblogs.com/wnsyou-blog/p/math.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   wnsyou  阅读(40)  评论(0编辑  收藏  举报
  1. 1 勝利への道 安藤浩和
  2. 2 Minecraft’s End Eric Fullerton
  3. 3 月光曲完整版 贝多芬 云熙音乐
  4. 4 平凡之路 (Live版) 朴树
  5. 5 Minecraft C418
  6. 6 Paradise NiziU
  7. 7 叫我,灰原哀 龙大人不喷火
  8. 8 心机之蛙,一直摸你肚子 ——《名侦探柯南》原创同人曲 炊饭,叶辞樱,温海,寒砧,南柯柯,小茜玛姬,盛姝,阿崔Ac,贝壳初,千湛,兮茶子DaYu,乔慕,黎鹿北,起千温卿,遮阳伞,曲悠
  9. 9 战 歌 此去经年
Minecraft - C418
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

暂无歌词

加载中…

{{tag.name}}

{{tran.text}}{{tran.sub}}
无对应文字
有可能是
{{input}}
尚未录入,我来提交对应文字
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示