扩展欧几里得求逆元以及逆元的应用

a x ≡ 1 (   m o d   m ) ax \equiv 1( \bmod m) ax1(modm)
a a a m m m互质,那么 x x x则为 a a a逆元
可推得式子:
a x + m y = 1 ax + my = 1 ax+my=1
利用扩展欧几里得求:

#include <bits/stdc++.h>
using namespace std;
int exgcd(int a, int b, int &x, int &y)
{
    if(!b) {
        x = 1;
        y = 0;
        return a;
    }
    int x1, y1, Gcd;
    Gcd = exgcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return Gcd;
}
const int mod = 19940417;

int main()
{
    int inv2, y;
    exgcd(2, mod, inv2, y);
    cout << "inv2: " << (inv2%mod+mod)%mod << "\ny: " << -y;
}

例题

题目链接

读完题,这不就是求逆元嘛
注意开long long

code:
#include <bits/stdc++.h>
#define int long long
using namespace std;

int exgcd(int a, int b, int &x, int &y)
{
    if(!b) {
        x = 1, y = 0;
        return a;
    }
    int x1, y1, Gcd;
    Gcd = exgcd(b, a % b, x1, y1);
    x = y1;
    y = x1 - a / b * y1;
    return Gcd;
}

signed main()
{
    int a, b;
    cin >> a >> b;
    int inv, y;
    exgcd(a, b, inv, y);
    cout << (inv % b + b) % b << endl;
}

例题二

原题链接

题意:

A B A^B AB的约数之和

Sol:

约数之和

一个数为 N N N: p 1 k 1 ∗ p 2 k 2 ∗ ⋅ ⋅ ⋅ ∗ p n k n p_1^{k_1} * p_2^{k_2} * ··· * p_n^{k_n} p1k1p2k2pnkn
约数个数: ∏ i = 1 n ( 1 + k i ) \prod_{i=1}^{n}(1 + k_i) i=1n(1+ki)
约数之和: ∏ i = 1 n ∑ j = 0 k i ( p j ) \prod_{i=1}^{n} \sum_{j=0}^{k_i}(p^j) i=1nj=0ki(pj)

分治法求 s u m ( p , k ) sum(p, k) sum(p,k):

p 0 + p 1 + p 2 + ⋅ ⋅ ⋅ + p k p^0 + p^1 + p^2 + ··· + p^k p0+p1+p2++pk
= ( p 0 + p 1 + ⋅ ⋅ ⋅ + p k 2 ) + p k 2 + 1 ∗ ( p 0 + p 1 + ⋅ ⋅ ⋅ + p k 2 ) (p^0 + p^1 + ··· + p^{\frac{k}{2}})+ p^{\frac{k}{2} + 1} * (p^0 + p^1 + ··· + p^{\frac{k}{2}}) (p0+p1++p2k)+p2k+1(p0+p1++p2k)
= ( 1 + p k 2 + 1 ) ∗ s u m ( p , k / 2 ) (1 + p^{\frac{k}{2} + 1}) * sum(p, k / 2) (1+p2k+1)sum(p,k/2)

Code1:
#include <bits/stdc++.h>

using namespace std;

const int mod = 9901;

int qpow(int a, int b)
{
    a %= mod;
    int ans = 1;
    while(b){
        if(b&1) ans = ans * a % mod;
        b>>=1; a = a * a % mod;
    }
    return ans;
}

int sum(int p, int k)
{
    if(k==0) return 1;
    if(k % 2 == 0) return (p % mod * sum(p, k - 1) + 1) % mod;
    return (1 + qpow(p, k / 2 + 1))% mod * sum(p, k / 2) % mod;
}

int main()
{
    int A, B; cin >> A >> B;
    int res = 1;
    for(int i = 2; i <= A ; ++i)
    {
        int s = 0;
        while( A % i == 0) s ++, A /= i;
        if(s) res = res * sum(i, s * B) % mod;
    }
    if(!A) res = 0;
    cout << res << endl;
}

公式法:
我们发现:
p 0 + p 1 + p 2 + ⋅ ⋅ ⋅ + p k p^0 + p^1 + p^2 + ··· + p^k p0+p1+p2++pk 就是一个等比数列求前n项和。
结果为:
p i k i ∗ B + 1 − 1 p i − 1 \frac{p_i^{k_i * B + 1} - 1}{p_i - 1} pi1pikiB+11
我们可以用快速幂求出分子,分母的逆元(存在的话)

根据费马小定理:
若p是质数,则对于任意整数a,有 a p − 1 ≡ 1 (   m o d   p ) a^{p-1}\equiv 1(\bmod p) ap11(modp)

所以:当模数p为质数的时候, b p − 2 b^{p-2} bp2即为 b b b的乘法逆元

特别的,如果不存在逆元,即 p [ i ] − 1 p[i] - 1 p[i]1是9901的倍数,此时乘法逆元不存在
但是 p i   m o d   9901 = 1 p_i \bmod 9901 = 1 pimod9901=1
所以:
1 + p i + p i 2 + ⋅ ⋅ ⋅ + p i B ∗ c i + 1 ≡ 1 + 1 + 1 2 + ⋅ ⋅ ⋅ + 1 B ∗ c i + 1 ≡ B ∗ c i + 1 (   m o d   9901 ) 1 + p_i + p_i^2 + ··· + p_i^{B * c_i + 1} \equiv 1 + 1 + 1^2 + ··· + 1^{B * c_i + 1} \equiv B * c_i + 1 (\bmod 9901) 1+pi+pi2++piBci+11+1+12++1Bci+1Bci+1(mod9901)

Code2:
#include <bits/stdc++.h>
#define int long long
using namespace std;

int a, b, m, ans = 1, mod = 9901;

int p[20], c[20];

void divide(int n)
{
    m = 0;
    for(int i = 2; i <= n / i; ++i)
    {
        if(n % i == 0)
        {
            p[++ m] = i;
            c[m] = 0;
            while(n % i == 0) ++ c[m], n /= i;
        }
    }
    if(n > 1) p[ ++ m] = n, c[m] = 1;
}

int qpow(int a, int b, int p)
{
    int ans = 1;
    while(b)
    {
        if(b & 1) ans = ans * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return ans;
}

signed main()
{
    cin >> a >> b;
    divide(a);
    for(int i = 1; i <= m; ++i)
    {
        if((p[i] - 1) % mod == 0) {
            ans = (b * c[i] + 1 ) % mod * ans % mod;
            continue;
        }
        
        int x = qpow(p[i], b * c[i] + 1, mod);
        x = (x - 1 + mod) % mod;
        int y = p[i] - 1;
        y = qpow(y, mod - 2, mod);
        ans = ans * x % mod * y % mod;
    }
    if(!a) ans = 0;
    cout << ans % mod << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W⁡angduoyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值