除法取模意义下的运算
逆元
如果整数 b b b, m m m互质,并且对于任意的整数 a a a,如果满足 a a a能被 b b b整除,记为 b ∣ a b|a b∣a,则存在一个整数 x x x,使得 a ÷ b ≡ a × x ( m o d m ) a \div b \equiv a \times x (mod \space m) a÷b≡a×x(mod m)。则称 x x x为 b b b模 m m m乘法逆元,记为 b − 1 ( m o d m ) b^{-1} (mod\space m) b−1(mod m)
如何求乘法逆元:
当 b b b存在乘法逆元的条件是 b b b与 m m m互质。当模数 m m m为质数的时候, b m − 2 b^{m - 2} bm−2为 b b b的乘法逆元
另一种定义:
a × x ≡ 1 ( m o d p ) a\times x \equiv 1 (mod p) a×x≡1(modp),且 g c d ( a , p ) = 1 gcd(a, p) = 1 gcd(a,p)=1,则称 a a a关于模 p p p的乘法逆元为 x x x
推导过程
记
b
b
b的逆元为
b
−
1
b^{-1}
b−1,故有:
a
b
×
b
m
o
d
p
=
a
×
b
−
1
×
b
m
o
d
p
{a \over b} \times b \space mod \space p = a \times b^{-1} \times b \space mod \space p
ba×b mod p=a×b−1×b mod p
左边消去分母有:
a
m
o
d
p
=
a
×
b
−
1
×
b
m
o
d
p
a \space mod p = a \times b^{-1} \times b \space mod \space p
a modp=a×b−1×b mod p
左右两边消去
a
a
a,有:
b
−
1
b
m
o
d
p
=
1
b^{-1}b \space mod \space p = 1
b−1b mod p=1
费马小定理:
b
p
−
1
m
o
d
p
=
1
b^{p-1} \space mod \space p = 1
bp−1 mod p=1
代入得:
b
−
1
b
≡
b
p
−
1
m
o
d
p
b^{-1}b \space \equiv b^{p-1} \space mod \space p
b−1b ≡bp−1 mod p
即:
b
−
1
=
b
p
−
2
m
o
d
p
b^{-1} = b^{p-2} \space mod \space p
b−1=bp−2 mod p
所以求
b
b
b模
p
p
p的逆元可以用快速幂求
b
p
−
2
m
o
d
p
b^{p-2} \space mod \space p
bp−2 mod p
快速幂
通过二分的方式在 l o g n logn logn的复杂度内求快速幂,由于可能溢出,所以每一次计算的时候要 m o d p mod \space p mod p
int quick(int a, int b, int p)
{
int res = 1;
while(b)
{
if(b & 1) res = (res * a) % p;
b >>= 1;
a = (a * a) % p;
}
return res;
}
如果是Python的话,可以用求 x x x在模 m m m下的逆元。
pow(x, -1, mod)
例题
排列组合知识:
-
长度为 l e n ( s ) len(s) len(s),不包含重复字符的字符串,将所有字符全排列构成的字符串数目是 l e n ( s ) ! len(s)! len(s)!
-
长度为 l e n ( s ) len(s) len(s),包含重复字符的字符串。重复字符的个数分别为 a , b , . . . , n a,b,...,n a,b,...,n。将所有字符全排列构成的字符串数目是 l e n ( s ) ! a ! × b ! × . . . × n ! len(s)!\over{a!}\times{b!}\times...\times{n!} a!×b!×...×n!len(s)!
分别计算分子和分母,在对分母做除法的时候用到上面的除法下的取模运算。
代码:
k, mod = 10 ** 5, 10 ** 9 + 7
fac = [1]
for i in range(1, k+1):
fac.append(fac[-1] * i % mod)
class Solution:
def countAnagrams(self, s: str) -> int:
words = s.split()
ans = 1
for word in words:
cnt = Counter(word)
ans *= fac[len(word)]
ans %= mod
for x in cnt.values():
ans *= pow(fac[x], -1, mod)
ans %= mod
return ans
class Solution {
const int MOD = 1e9 + 7;
long pow(long x, int n) {
long res = 1L;
for (; n; n /= 2) {
if (n % 2) res = res * x % MOD;
x = x * x % MOD;
}
return res;
}
public:
int countAnagrams(string &s) {
long ans = 1L, mul = 1L;
int cnt[26]{};
for (int i = 0, j = 0; i < s.length(); ++i) {
if (s[i] == ' ') {
memset(cnt, 0, sizeof(cnt));
j = 0;
} else {
mul = mul * ++cnt[s[i] - 'a'] % MOD;
ans = ans * ++j % MOD;
}
}
return ans * pow(mul, MOD - 2) % MOD;
}
};
作者:灵茶山艾府
链接:https://leetcode.cn/problems/count-anagrams/solutions/2031837/zu-he-ji-shu-by-endlesscheng-leem/
来源:力扣(LeetCode)