基本公式
公式: (a*b)%n = (a%n * b%n)%n。(a,b,n都是整数)
证明:假设公式成立,且构造:a = q *n+r , b=p *n+s。(假设法)
然后a * b = q * p*(n^2)+q * s * n+r * p * n+r * s。
其中, q * p*(n^2) % n = 0(可以直接商q *p *n,余数就是0)
于是两边同时使用公式,右边为:0+(r * s)%n,
又因为,a%n=r,b%n=s,所以左边为:(r * s)%n
故左右式恒等,假设成立。(若假设不成立,左右式不一定相等)
公式:(a+b)%n = (a%n + b%n)%n ,证明方式和上面一样。
快速幂中的取余
快速幂的代码:
long long qmi(long long a, int b) {
long long res = 1;
while (b) {
//逻辑:a^b = (a*a)^(b/2)
//两个修正:(如下是计算机的/)
//b为奇数,a^b = a*a^(b-1) = a*(a*a)^(b/2)
//b = 1 -> 赋值给res
if (b & 1) res = (res * a) % mod;
a = (a * a) % mod;
b >>= 1;
}
return res;
}
其中的取余逻辑:(令:d = a%n * b%n )
(a * b* c)% n = ((a * b)%n * c %n )% n = ((a%n * b%n)%n * c %n )% n =(b%n * c %n )% n = (d*c)%n
所以,每一个项都可以直接%n,然后进行整合。
当然,加法也可也可以,证明同上。但是除法要涉及逆元概念,因为:除以一个数就相当于乘以它的倒数
逆元中的取余
在前缀和的逻辑下,我们有时候需要处理前缀乘。由于数据过大,我们需要对一个质数取余,然后一般就会把取余后的数据存入数组。
然后我们需要求一个数除以另一个数,代码:
sum = a[j]*qmi(a[i-1],mod-2)%mod; //qmi返回的数据也是取余后的。
首先,逆元的概念:(a*b)%n = 1%n;那么b就是a在n下的逆元。所以,/a可以等价于 * b。
然后求b,通过费马小定理 a * a^(n−2) ≡a^(n−1)≡1 (mod n),可以知道b = a^(n-2)
最后解释:a^(n−1)≡1 (mod n),其中: n 是质数 。
首先引入完全剩余系的概念:完全剩余系指集合A的元素对n取余能得到0…n-1的所有整数,如A={0,1,2,3,9},B={5,6,7,8,4},它们都是5的完全剩余系。以及一个式子:a * c ≡ b * c (%n) ->(a%n * c%n) = (b %n * c%n ) -> a ≡ b (%n)。
然后构造n得剩余系p={1,2,…n-1}。它有(n-1)个数,如果每一个元素都乘以a,然后再把每个元素相乘,就出现了费马小定理中的a^(n−1)。于是构造一个普通集合:A={a,2*a…(n-1) * a}。把p中元素记为b,我们发现:如果存在:a * b[i] ≡ a * b[j] (%n) ,那么就有:b[i] ≡ b[j] (%n),但p是n的剩余系 b[i] ≡ b[j] (%n)是不成立的,故而a * b[i] ≡ a * b[j] (%n)不成立,于是得到A也是n的剩余系。然后对每一个元素做取余相乘的操作,就会有p=A,即:(n-1)! ≡ (n-1)! * a^(n-1) (%n),约掉(n-1)!得到:1 ≡ a ^ (n-1) (%n)也就是:a^(n−1)≡1 (mod n) 。
总结:感觉整个过程就是通过构造的方式去获得一些式子或者定理去接近结论。可以在思维上用贪心思维,分开去找某一部分的式子。以及,互质在取余中真的很重要,因为互质,所以*1 然后式子就被消掉了。