前言
在一些题目中,因为数据量会特别大甚至超过long long
,所以会要求最后结果mod
一个数,实际上就是让你在计算过程中就要不断mod。
对于加法:
(
a
+
b
)
%
m
=
(
a
%
m
+
b
%
m
)
%
m
(a+b)\%m = (a\%m+b\%m)\%m
(a+b)%m=(a%m+b%m)%m
对于减法:
(
a
−
b
)
%
m
=
(
a
%
m
−
b
%
m
)
%
m
(a-b)\%m = (a\%m-b\%m)\%m
(a−b)%m=(a%m−b%m)%m
对于乘法:
(
a
∗
b
)
%
m
=
(
a
%
m
∗
b
%
m
)
%
m
(a*b)\%m = (a\%m*b\%m)\%m
(a∗b)%m=(a%m∗b%m)%m
但是这个规则在除法不适用:简单例子比如 ( 30 7 ) % 2 (\frac{30}{7})\%2 (730)%2。
我们一般遇到除法 (a/b)%MOD
的时候,会将除法变为乘法,用到了“逆元”的思想。
逆元
当求解公式:(a/b)%m
时,因b可能会过大,会出现爆精度的情况,所以需变除法为乘法:
设c是b的逆元,则有b*c≡1(mod m);
则(a/b)%m = (a/b)*1%m = (a/b)*b*c%m = a*c(mod m);
例如: b = 10 , m = 3 b=10,m=3 b=10,m=3时, c = 4 c=4 c=4
令
a
=
20
,
(
20
/
10
)
%
3
=
2
,
(
20
∗
4
)
%
3
=
2
a=20, (20/10)\%3=2 ,(20*4)\%3=2
a=20,(20/10)%3=2,(20∗4)%3=2
令
a
=
40
,
(
40
/
10
)
%
3
=
1
,
(
40
∗
4
)
%
3
=
1
a=40, (40/10)\%3=1 ,(40*4)\%3=1
a=40,(40/10)%3=1,(40∗4)%3=1
现在我们要求 ( a / b ) % m (a/b)\%m (a/b)%m,可以找到一个 c c c使得 ( a / b ) % m = ( a ∗ c ) % m (a/b)\%m=(a*c)\%m (a/b)%m=(a∗c)%m.
费马小定理
如果 p p p是一个质数,而整数 a a a不是 p p p的倍数,则有 a p − 1 ≡ 1 ( m o d ) p a^{p-1} ≡ 1(mod)p ap−1≡1(mod)p
所以可得: a p − 2 ≡ a − 1 ( m o d p ) a^{p-2}≡a^{-1}(mod p) ap−2≡a−1(modp)
换成代码如下:
(a/b)%m
(a*pow(b,m-2))%m
这里还需要快速幂来配合计算:
ll quick_pow(ll x,ll n,ll m)
{
ll res = 1;
while(n > 0)
{
if(n & 1)
res = res * x % m;
x = x * x % m;
n >>= 1;
}
return res;
}
ll inv(ll a)
{
return quick_pow(a, mod - 2, mod);
}
递归
当m是质数,inv(a) = (m - m / a) * inv(m % a) % m
,暴力反向递归
ll inv2(ll a,ll m)//代入a%m m
{
return a==1?1:(m-m/a)*inv2(m%a,m)%m;
}
线性递推
求关于一个m的多个逆元,道理差不多:
ll m=3;
ll inv[m+5];
void inv3(ll m)
{
inv[1]=1;
for(int i=2;i<m;i++)
inv[i]=(m-m/i)*inv[m%i]%m;
}
参考:Link
加油!
感谢!
努力!