1. 程式人生 > 實用技巧 >有理分式的取模運算

有理分式的取模運算

引出
一些取模的基本運算:
(a+b)%p=(a%p+b%p)%p
(a-b)%p=(a%p-b%p)%p
(a×b)%p=(a%p×b%p)%p
(a/b)%p=(a%p/b%p)%p

一些符號的說明
: a≡b(mod p) 表示 a和b分別模p,餘數相同,即a和b對p取模同餘

乘法逆元的定義
若在mod p意義下,對於一個整數a,有a*p≡1(mod p),那麼這個整數x即為a的乘法逆元,同時a也為x的乘法逆元

充要條件
a存在模p的乘法逆元的充要條件是gcd(a,p)=1,即a與p互質

有理分數的取模
求取(a/b)%p 等同於 a(b的逆元)%p
證明:
設b的x的逆元為x,即b

x≡1(mod p)
對於式① (a/b)%p=m
①×b得② a%p=mb %p
②×x得③ a
x=mbx %p
即 ax≡mbx (%p)
又因為  b
x≡1(%p)
所以 ax≡m(%p)
因此 (a/b)%p=m 也就是 a
x≡m(%p)

逆元的求解
費馬小定理:假如a是一個整數,p是一個質數,那麼
1.如果a是p的倍數,a^p≡a(%p)
2.如果a不是p的倍數,a^(p-1)≡1(%p)
又因a存在模p的乘法逆元的充要條件是gcd(a,p)=1,所以a肯定不是p的倍數,因此
a^(p-1)≡1(%p)
即 aa^(p-2)≡1(%p) a^(p-2)就是a的乘法逆元
a%p

(a^(p-2)%p)=1%p

有理分數的取模運算
綜上所述,得出結論:
(b/a)%p=(ba的逆元)%p=(ba^(p-2))%p

程式碼實現
程式碼出自:https://www.jianshu.com/p/d0a083a7e4c1

public class Mod {

    public static final long MOD = 1_000_000_007;

    /**
     * 模乘
     * @param x
     * @param y
     * @return x * y % MOD
     */
    public static long mul(long x, long y) {
        return ((x % MOD) * (y % MOD)) % MOD;
    }

    /**
     * 模加
     * @param x
     * @param y
     * @return (x + y) % MOD
     */
    public static long add(long x, long y) {
        return  ((x % MOD) + (y % MOD)) % MOD;
    }

    /**
     * 模快速冪
     * @param x
     * @param n
     * @return x^n % MOD
     */
    public static long quickPower(long x, long n) {
        if (n == 0) return 1;
        if (n == 1) return x % MOD;
        long tmp = quickPower(x, n >> 1);
        return (n & 1) == 0 ? mul(tmp, tmp) : mul(x, mul(tmp, tmp));
    }

    /**
     * 分數求模
     * 費馬小定理 a^(p-1) mod p = 1 mod p
     * a * a^(p-2) mod p = 1 mod p
     * a^(p-2) mod p = a^(-1) mod p
     * (b/a) % p = b * a^(-1) % p = b * a^(p-2) % p
     * @param a 分母
     * @param b 分子
     * @return (b/a) % MOD
     */
    public static long fractionMod(long a, long b) {
        return mul(b, quickPower(a, MOD-2));
    }

}