先言
本篇文章部分内容进行了相互穿插,请结合目录食用 。 如有不便,望见谅。
模运算
顾名思义 , 在模意义下进行运算,满足普通加法减法乘法运算 。
例如 \(a + b = c (mod \ \ p) => a\ \ mod \ \ p + b \ \ mod = c (mod \ \ p)\) 拿一个具体数字 , 即为
\(5 + 7 = 5 (mod \ \ 7) => 5 \ \mod \ \ 7 + 7 \ \ mod \ \ 7 = 5 + 0 = 5 (mod \ \ 7)\)
减法同样如此,但是在减法进行计算的时候,有可能会变成负数,但我们尽量不想让其变成负数,那我们可以转化成这样 $ ( (a - b )mod \ \ c + c )mod \ \ c$ 与 \((a - b) mod \ \ c\) 在模意义下是满足相等的。
除法则是满足不满足的,只有当 \(p\) 为质数时, 才可以进行 。
快速幂
幂运算就是 \(a^b\) 这样的运算 。快速幂就是将 \(a^b\) 转化成 \((a ^{\frac{b}{2}} )^2\) ,从而达到快速计算,同时对 \(b\) 进行一下讨论是否为奇数。
\(Code\) 模板
int quick_pow(int a , int b , int p) //a ^ b % p
{
int ret = 1 ;
while(b)
{
if(b & 1) ret = ret * a % p ; //指数为奇数 。
a = a * a % p ;
b >>= 1 ;
}
return ret ;
}
模板题 【\(Code\)】
略微推一下出来的模板题 【\(Code\)】
素数(质数)
定义就是只能够被 \(1\) 或者他自身整除的数字 。
判定
\(1.\)判断一下 $2 \to n - 1 $ 是否能为 \(n\) 的因子 ,复杂度 \(O(n)\)
n 一定能够被分解成\(a \times b\) 我们假设 \(a < b\) 那么我们只需要枚举 \(a\) 即可,因为如果 \(a\) 不满足乘除 \(n\) ,那么也不会有其它数能乘除 \(n\) ,同时 可以显然 \(a\) 的上界为 \(\sqrt n\)
\(2.\) 判断一下 \(2 \to \sqrt n\) ,看一下能否为 \(n\) 的因子,复杂度 \(O(\sqrt n)\)
筛法
算术基本定理
\(x = \prod p_{i} ^ {c_i}\) \(p_i\) 是个质数 。对于任意的 \(x\in N\) 均满足上述式子,也就是每个数,都能被分解成几个质数和质数的平方的乘积 。
具体证明或者其他,详见此博客
质数分布定理
\(1 \to n\) 的质数个数大约是: $ \frac{x}{\ln(x)}$ , 其数学中给出了详细且严谨的证明,\(OI\) 就不必深究其证明了
\(1.\) 试除法筛素数 ,
原理:枚举 \(1 \to n\) 这些所有的数, 同时,再用试除法 \(2\to \sqrt n\) 来判断一下第 \(i\) 个数是否为素数 ,预计复杂度 \(O(n \times \sqrt n)\)
\(2.\) 埃氏筛
原理 : 就是由于素数的倍数必然不是一个质数,那么我们在枚举到一个质数的时候,我们将它的所有倍数删除掉,那么剩下的,就是质数了 , 复杂度 : \(O(n\times \log(\log n))\)
for(int i = 2 ; i <= n ; i++)
{
if(!vis[i])
{
prime[++tot] = i ;
for(int j = i ; j * i <= n ; j++)
{
vis[i * j] = 1 ;
}
}
}
\(3.\) 线性筛
原理和埃氏筛一致,都是删去素数的倍数从而使得剩下便是质数,那么它是埃氏筛的进一步优化。也就是让所有的数都只被访问一遍。
实现:让所有的数都只被访问一遍,也就是只被输出一遍,那么我们让它只能被它的最小质因子访问。
for(int i = 2 ; i <= n ; i++)
{
//不管 i 是否为质都要筛掉其它数字
//从小到大枚举素数
for(int j = 0 ; j < tot ;j++ 删去 prime * i)
{
int p = prime[j] ;
//筛掉 i * p
//保证p是最小i*p素因子
if(p == 是i的最小质因子) break ;
}
}
实际代码
for(int i=2;i<=n;i++)
{
if(!num[i])
{
a[cnt++]=i; //统计其中的素数
}
for(int j=0;j<cnt&&i*a[j]<=n;j++)
{
num[i*a[j]]=1;//删除其素数的倍数
if(i%a[j]==0)//保证是最小质因子
{
break;
}
}
}
gcd , lcm
一些约定
我们规定\(gcd(x,y)\)表示的是\(x,y\)的最大公约数,同时\(lcm(x,y)\)规定为最小公倍数。
规定\(a|b\)表示\(a\)能够乘除\(b\)。
规定\(a \ \ mod \ \ b\)表示\(a\) %\(b\)
求解
\(1.\) 辗转相除法(欧几里得算法)
先来看一下其递归式
gcd(int a , int b)
{
return !b ? a : gcd(b , a % b) ;
}
其复杂度是 \(O(log)\) 的
证明
证明 \(gcd(a , b) = gcd(b , a\text{%}b)\)
设 \(r = a \text{%}b , d = gcd(a , b),a = p1\times d , b = p2\times d\)
其中 \(p1,p2\) 互质(这个比较显然吧,不互质的话还有公约数,那么就不是最大公约数了 ,那么我们就可以得到
\(r = a\text{%}b = a - k \times b = p1\times d - k\times p2 \times d = (p1 - k\times p2) \times d\) , 所以首先我们可以确定 \(r\) 一定是个 \(d\) 的倍数。
感性理解一下,由于我们搞出来的\(a \text{%} b\)是单调不增的,那么我们的值一旦找到,可不就是最大的。
又因为 \(b = p2 \times d\)
我们只需说明 \(p2 , p1 - k\times p2\) 互质即可说明 \(d\) 一定为最大公约数,
证明 \(p2 , p1 - k\times p2\) 互质:
假设 \(p2 . p1 - k\times p2\) 不互质。那么我们就有
把 \(p2 = m\times q\) 带入可知
所以 \(a = p1\times d , b = p2\times d\) 则\(a = (k\times m + n)q \times d , b = m\times q \times d\)
则 \(a , b\) 的最大公约数为 \(q\times d\) , 则与假设不符,不成立,所以 \(p2 , p1-k\times p2\) 互质。所以 \(r\) 和 \(b\) 的公约数也就是 \(d\)
所以 \(gcd(a, b) = gcd(b , a\text{%}b)\)
联系
那么 \(lcm\) 和 \(gcd\) 有什么关系呢?
令 \(x = gcd(a,b)\).
则显然 \(x \mid a\),\(x\mid b\).
令 \(a_0 = [a\ / \ x]\ , \ b_0 = [b\ /\ x]\).
则 \(lcm(a_0 \ , \ b_0) = a_0 \times b_0\). \(gcd(a_0,b_0) = 1\)
\(lcm(a_0,b_0) \times gcd(a_0,b_0) \times x = a_0 \times b_0 \times x\)
又因为 ,最大公约数
所以 , \(lcm(a,b)= \frac {a \times b}{x}\)
也就是 \(lcm(a,b) \times x = a \times b\)
所以 , \(lcm(a,b) \times gcd(a,b) = a \times b\)
证毕,$over \ ~ \ $
整除
【定义】: 如果\(x\) % \(y==0\) , 我们就说, \(y\)整除\(x\) ,记做(上方有约定,但是还是说一下) , \(y|x\) ,
【性质】 :(从数竞同学那里嫖来的)
1.若\(b|a\) ,则\(b|(-a) , -b|a , (-b) |(-a) , |b| \ \ | \ \ |a|\) (最后面的是两个绝对值)
2.满足转移性: 若\(a|b\) , \(b|c\) ,则\(a|c\)
3.若\(a,b,c\in Z\) ,且\(a|b , a|c\),则\(a|(b±c) , a| mb , a | mc , a | m(b±c)\),(\(mb\)代表\(m \times b\),没有骂人的意思,也不是\(mb\)那一个变量的意思,不会吧,不会吧,还有人不知道吗?)
我们可以将其进行一下推广到一般情况:
若\(a_i,b_i,c_i \in Z , i = 1 , 2 , 3 … n\),并且满足\(a_i | b_i\),则有\(a|\sum\limits_{i=1}^{n} b_i \times c_i\),比较显然吧。
4.设\(a,b\in Z\),且\(a|b\) ,则对于任意的\(m \in Z\) ,都满足\(am | bm\) ,这是个充要条件。
5.若\(|a| < |b|\) , 且\(|b| \ \ | \ \ |a|\) ,则\(a = 0\)
6.若\(a,b\)互素,且\(p|\prod\limits_{i = 1}^{n} a_i\),则在\(a_1 ,a_2…a_n\)中,至少有一个\(a_i\),满足\(p\ \ | \ \ a_i\)
7.若\(a,b\)互素,且\(a|b\times c\) ,则\(a|c\)
8.\(n\)个连续整数的乘积必然能被\(n!\)整除。
9.若\(p\)为素数,对任意的正整数\(n\),都满足\(p | (n ^p - n)\).这性质叫做费马小定理,证明在求解逆元时会予以证明。
逆元
求解逆元的方法
什么叫做逆元 , 我们认为 \(a \times a^{-1} = 1 (mod \ \ p)\) ,我们称 \(a^{-1}\) 为 \(a\) 模 \(p\) 意义下的逆元
\(1.\) 递推求解逆元
假设 \(p = k\times i + r| i > r\)
对两边同时乘上 \(i^{-1} , r^{-1}\) 就得到
然后就有了
同时,\(i > r\) ,这就形成了线性递推关系
// 求 1 -> n的逆元
inv[i] = 1 ;
for(int i = 2 ; i <= n ; i++)
{
inv[i] = (-p/i + p ) * f[p % i] ;
}
\(2.\) 费马小定理求解逆元。
证明费马小定理的正确性:
(事实证明,证不出来背过亦可)
占个坑 , 以后证完补。
然后就是一个快速幂的事,不必附代码
\(3.\) 扩欧求求解逆元。
占个坑,等讲完之后有了更深的理解再写。
逆元的应用
可以进行模意义下除法,我们在模意义下是不能进行除法的,但是我们可以利用逆元将除法转化成乘法,就行了。
为什么模意义下不能进行除法,因为会导致出现实数,而余数显示不能为小数。
扩展欧几里得算法
先证明出欧几里得显然在这里变得是比较重要。
鸣谢 : 欧几里得算法与扩展欧几里得算法_C++
引理
扩展欧几里得是用来求解线性同余方程 ,逆元,不定方程的一种算法。
引理 : 对于任意的整数 \(a,b\) ,存在 \(x,y\) 使得 \(gcd(a,b) = a\times x + b\times y\)
证明
当 \(b = 0\) 时 , \(gcd(a,b) = a\) , 此时 , \(x = 1 , y = 0\)
当 \(b\not = 0\) 时
当 \(b = 0\) 时会得到最后的一组解,其他的均可以又上述的推导出来。
代码实现
inline void exgcd(int a , int b , int x , int y)
{
if(!b)
{
x = 1 , y = 0 ;
return ;
}
else
{
exgcd(b , a%b , x , y) ;
int k = x ;
x = y ;
y = k - (a / b) * y;
}
}
没有啥模板题让着写这玩意证明的。
exgcd 求解不定方程
【鸣谢】
对于一个 \(a\times x + b\times y = c\) 这一个不定方程, \(d = gcd(a,b)\) ,那么显然的 , \(d|(a\times x + b\times y)\) , 所以,如果 \(c\text{%}d \not = 0\) , 那么就说明是无解的。如果有解的话 :
我们能够推出一组特解。
很显然,我们是有 \(a\times x_1+ b\times y_1 = d\) , 同样的,我们设 \(q \times d = c\) , 将上述式子乘以 \(q\) , 则有
这样就得到一组特殊解,我们通过特殊解进行推导通解。
我们推导一般的式子,即为
那么我们让 \(a\times m + b\times n = 0\) ,就可以满足上述的式子了。
所以我们就有 \(a\times m = -b\times n\) , 同理可以得到 , \(m = t \times \frac{b}{a} , n = -t\times \frac{a}{b}\) , 其中 \(t\) 为任意取得。
exgcd 求线性同余方程
关于一个模方程 \(a \times x \text{%} b = c\) 求解。
我们可以将其转化成
同理, 就可以得到
然后发现这是一个不定方程,很鸡贼,和上面一致即可。
【模板题】
【\(Code\)】
【青蛙的约会】
【\(Code\)】