1 条题解

  • 0
    @ 2025-8-24 21:52:59

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar zjp_shadow
    AFO

    搬运于2025-08-24 21:52:59,当前版本为作者最后更新于2017-12-10 08:38:05,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    乘法逆元小结

    乘法逆元,一般用于求 $$\frac{a}{b} \pmod p$$ 的值(pp 通常为质数),是解决模意义下分数数值的必要手段。

    有兴趣可以点进我的博客看看啊qwq

    逆元定义

    ax1(modb)a*x\equiv1 \pmod {b},且aabb互质,那么我们就能定义: xxaa 的逆元,记为a1a^{-1},所以我们也可以称 xxaamodb\bmod b 意义下的倒数,

    所以对于 ab(modp)\displaystyle\frac{a}{b} \pmod {p} ,我们就可以求出 bbmodp\bmod {p} 下的逆元,然后乘上 aa ,再 modp\bmod {p},就是这个分数的值了。

    求解逆元的方式

    拓展欧几里得

    这个方法十分容易理解,而且对于单个查找效率似乎也还不错,比后面要介绍的大部分方法都要快(尤其对于 modp\bmod {p} 比较大的时候)。

    这个就是利用拓欧求解 线性同余方程 axc(modb)a*x \equiv c \pmod {b}c=1c=1的情况。我们就可以转化为解 ax+by=1a*x + b*y = 1 这个方程。

    求解这个方程的解。不会拓欧可以点这里~

    而且这个做法还有个好处在于,当 apa \bot p (互质),但 pp 不是质数的时候也可以使用。

    代码比较简单:

    void Exgcd(ll a, ll b, ll &x, ll &y) {
        if (!b) x = 1, y = 0;
        else Exgcd(b, a % b, y, x), y -= a / b * x;
    }
    int main() {
        ll x, y;
        Exgcd (a, p, x, y);
        x = (x % p + p) % p;
        printf ("%d\n", x); //x是a在mod p下的逆元
    }
    

    快速幂

    这个做法要利用 费马小定理

    pp为素数,aa为正整数,且aapp互质。 则有ap11(modp)a^{p-1} \equiv 1 (\bmod {p})

    这个我们就可以发现它这个式子右边刚好为 11

    所以我们就可以放入原式,就可以得到:

    ax1(modp)a*x\equiv 1 \pmod p axap1(modp)a*x\equiv a^{p-1} \pmod p xap2(modp)x \equiv a^{p-2} \pmod p

    所以我们可以用快速幂来算出 ap2(modp)a^{p-2} \pmod p的值,这个数就是它的逆元了

    代码也很简单:

    ll fpm(ll x, ll power, ll mod) {
        x %= mod;
        ll ans = 1;
        for (; power; power >>= 1, (x *= x) %= mod)
        	if(power & 1) (ans *= x) %= mod;
        return ans;
    }
    int main() {
    	ll x = fpm(a, p - 2, p); //x为a在mod p意义下的逆元
    }
    

    线性算法

    用于求一连串数字对于一个modp\bmod p的逆元。洛谷P3811

    只能用这种方法,别的算法都比这些要求一串要慢。

    首先我们有一个,111(modp)1^{-1}\equiv 1 \pmod p

    然后设 p=ki+r,(1<r<i<p)p=k*i+r,(1<r<i<p) 也就是 kkp/ip / i 的商,rr 是余数 。

    再将这个式子放到(modp)\pmod p意义下就会得到:

    ki+r0(modp)k*i+r \equiv 0 \pmod p

    然后乘上i1i^{-1},r1r^{-1}就可以得到:

    kr1+i10(modp)k*r^{-1}+i^{-1}\equiv 0 \pmod p i1kr1(modp)i^{-1}\equiv -k*r^{-1} \pmod p $$i^{-1}\equiv -\lfloor \frac{p}{i} \rfloor*(p \bmod i)^{-1} \pmod p $$

    于是,我们就可以从前面推出当前的逆元了。

    代码也很短:

    inv[1] = 1;
    for(int i = 2; i < p; ++ i)
        inv[i] = (p - p / i) * inv[p % i] % p;
    

    阶乘逆元 O(n)O(n)

    因为有如下一个递推关系。

    inv[i+1]=1(i+1)!\displaystyle inv[i+1]=\frac{1}{(i+1)!}

    inv[i+1](i+1)=1i!=inv[i]\displaystyle inv[i+1]*(i+1)=\frac{1}{i!}=inv[i]

    所以我们可以求出n!n!的逆元,然后逆推,就可以求出1...n!1...n!所有的逆元了。

    递推式为

    inv[i+1](i+1)=inv[i]inv[i+1]*(i+1)=inv[i]

    所以我们可以求出 i,i!,1i!\displaystyle \forall i, i!,\frac{1}{i!} 的取值了。

    然后这个也可以导出 1i(modp)\displaystyle \frac{1}{i} \pmod p 的取值,也就是

    $$\displaystyle \frac{1}{i!} \times (i - 1)! = \frac{1}{i} \pmod p $$

    具体实现可以参考我这发提交(卡了常。。)

    • 1

    信息

    ID
    2770
    时间
    500ms
    内存
    125MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者