除法取模意义下的运算

除法取模意义下的运算

逆元

如果整数 b b b, m m m互质,并且对于任意的整数 a a a,如果满足 a a a能被 b b b整除,记为 b ∣ a b|a ba,则存在一个整数 x x x,使得 a ÷ b ≡ a × x ( m o d   m ) a \div b \equiv a \times x (mod \space m) a÷ba×x(mod m)。则称 x x x b b b m m m乘法逆元,记为 b − 1 ( m o d   m ) b^{-1} (mod\space m) b1mod m

如何求乘法逆元:

b b b存在乘法逆元的条件是 b b b m m m互质。当模数 m m m为质数的时候, b m − 2 b^{m - 2} bm2 b b b的乘法逆元

另一种定义:

a × x ≡ 1 ( m o d p ) a\times x \equiv 1 (mod p) a×x1(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} b1,故有:
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×b1×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×b1×b mod p
左右两边消去 a a a,有:
b − 1 b   m o d   p = 1 b^{-1}b \space mod \space p = 1 b1b mod p=1
费马小定理:
b p − 1   m o d   p = 1 b^{p-1} \space mod \space p = 1 bp1 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 b1b bp1 mod p
即:
b − 1 = b p − 2   m o d   p b^{-1} = b^{p-2} \space mod \space p b1=bp2 mod p
所以求 b b b p p p的逆元可以用快速幂求 b p − 2   m o d   p b^{p-2} \space mod \space p bp2 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)

例题

力扣2514 统计同位异构字符串数目

排列组合知识:

  • 长度为 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)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值