前言
写这篇文章的时候,本蒟蒻正在挑战3个月达省一;
之前一直对模运算耿耿于怀十分好奇,遂决定,今天拿下;
最后在正文开始之前放一个搞笑的东西:
关于模运算的定义
我们先定义带余除法 (其实就是除法):
\(设两个数 a,m \in \symbb{Z}, m \not= 0,则a、m的带余除法定义为:\)
存在唯一的整数q、r(r必须大于等于0),使得
\[a = qm+r \]
我们记a模m为: \(a \bmod m\)
我们把 \(q\) 称做商,\(r\) 称做余数(也称a模m的结果),记作:
\[r = a \bmod m \]
关于114514 & 998244353
在 OI 中,模运算最直接的用处就是解决一些需要处理带模运算的题目;
而 \(114514\) 和 \(998244353\) 这两个神奇的模数就不得不提一下了:
\(114514\) 请自行百度(主要是我也没查出来什么), \(998244353\) 有如下的几个特点:
1.它的二进制表达是:111011100000000000000000000001
2.它是一个质数。
3.它是一个奇数。
4.它可以表达为两个数的平方和:\(998244353 = 3943^2 + 31348^2\)
5.它是勾股数之一:\(998244353^2 = 247210328^2 + 967149855^2\)
6.它可以被表达为:\(998244353 = 7 \times 17 \times 2^{23} + 1\)
7.998244353最优美的性质莫过于它是个完美恶臭数:
\[998244353=( 114514 * ( 54-1+114 * (1+14*5+1+4) ) ) + ( 4+11451 * (4-1-15+14) ) + ( 11+41*54 + (141+541) ) + (4-1-15+14) \]
之所以称为完美,因为每一个括号里114514都出现了正整数次;
Tips :\(998244353\) 最大的一个特点是:出题人 \(99\%\) 的情况下是不会使用这个数的,取而代之的是 \(998234353\) 、\(998244553\) ,不过应该没人会栽在上面
模运算的两个等式
\[\S 1. (a+b) \bmod m = ((a \bmod m)+(b \bmod m)) \bmod m \]
\[\S 2. (a \times b) \bmod m = ((a \bmod m) \times (b \bmod m)) \bmod m \]
这两个是经常会用到的等式,大部分的OI题目都要求取模
但是通常情况下,这时的结果都远远超出了int型的范围,我们需要在运算过程中就直接取模,而这步的正确性就是依赖于上面的两个等式
下面我们来证明一下:
证明1:
依据带余除法,我们设 \(a = q_1m + r_1,\) \(b = q_2m + r_2\),那么带入等式左边,我们有:
\[(a+b)\bmod m = (q_1m+r_1+q_2m+r_2) \bmod m \]
更进一步,合并同类项:
\[原式 = ((q_1+q_2)m+r_1+r_2) \bmod m \]
引入一个定理:
\(a \bmod m\) 的结果与 \((a+k \times m) \bmod m\) 是一样的,通俗来说,就是一个数除以另一个数的余数,与这个数加上任意倍的除数之后除以除数的余数是一样的
显然,这里相当于有一个商为 \((q_1+q_2)\) ,余数为 \(r_1+r_2\) 的数模 \(m\) ,当然就等于直接对 \(r_1+r_2\) 模 \(m\) (不妨自己试一下,\(9 \bmod 2\) 和 \(1 \bmod 2\)一不一样)
所以我们有:
\[((q_1+q_2)m+r_1+r_2) \bmod m = (r_1+r_2) \bmod m \]
而 \(r_1,r_2\) 就是 \(a \bmod m\) ,\(b \bmod m\) ,带入得:
\[(r_1+r_2) \bmod m = ((a \bmod m)+(b \bmod m)) \bmod m \]
证毕
证明2:
仍然依据带余除法,我们设 \(a = q_1m + r_1,\) \(b = q_2m + r_2\),那么带入等式左边,我们有:
\[(a \times b)\bmod m = ((q_1m+r1) \times (q_2m + r_2)) \bmod m \]
展开:
\[= (q_1q_2m^2+(q_1r_2+q_2r_1)m+r_1r_2) \bmod m \]
这里括号内的前两项仍然是 \(m\) 的倍数,所以可以和1一样进行替换
\[= (r_1r_2) \bmod m \]
而 \(r_1\) 、\(r_2\) 分别是 \(a \bmod m\) ,\(b \bmod m\) ,带入得:
\[= ((a \bmod m) \times (b \bmod m)) \bmod m \]
证毕
同余
如果在计算过程中出现了负数,应该如何处理呢(也就是对负数取模,这里不能直接取,这样是负的)?
我们回归问题的本质:求出这个负数除以m的余数
也就是说,我们只要找到一个和这个负数除以m的余数一样的正数,就可以找到这个负数除以m的余数,而所谓的"和这个负数除以m的余数一样的正数",简称和这个负数同余(具有同样的余数)
当然,仅说同余是没有意义的,我们需要指定模数(除数),才是有意义的;
具体而言:假如有两个整数 \(x,y\) ,若 \((x-y) \bmod m = 0\) ,则称 \(x,y\) 在模 \(m\) 意义下同余(具有同样的余数)
为什么差是倍数就同余呢 ,仍然依据带余除法,我们设 \(x = q_1m + r_1,\) \(y = q_2m + r_2\),那么带入等式左边,我们有:
\[原式 = ((q_1-q_2)m+(r_1-r_2)) \bmod m \]
而因为这玩意为0,所以 \((q_1-q_2)m+(r_1-r_2)\) 必然是 \(m\) 的倍数,也就是能写成 \(n \times m\)的形式( \(n\) 是一个整数),显然,\(n = q_1-q_2\) ,所以 \(r_1 - r_2 = 0\),也就是说,\(r_1 = r_2\) ,即 \(x,y\) 同余;
现在给出定义:对于任意的两个数 \(x,y\) ,若有 \((x-y) \bmod m = 0\) ,那么我们称 \(x,y\) 在模 \(m\) 意义下同余,记为:
\[x \equiv y\pmod m \]
那么回到最初的问题:如何找到和这个负数同余的正数;
我们假设这个数是 \(-15\),根据同余的定义,我们有:\(-15 \equiv 5 \pmod{10}\) (\(-15-5 = -20 \bmod 10 = 0\) ,显然-20是10的-2倍)
那么怎样从 \(-15\) 推出 \(5\) 来呢?
我们使用 「模m加m」 的方法,即先模m得到一个负数,随后加上m,就得到了和m同余的正数:
\(-15 \bmod 10 = -5\),\(-5+10 = 5\),这样就得到了5,随后再对5模10即可(这里的负余数-5是大部分的编程语言的默认做法,但是不符合数学定义);
对于对一个不知正负的数字 \(x\) 取模,我们进行如下计算:
\(x \bmod m = (x \bmod m + m) \bmod m\)
最后
到这里这篇介绍模运算的文章就结束了(当然不包含对除法的取模,这个比较复杂,需要适当了解群论和乘法逆元),可能会有笔误,欢迎各位指正