数论倒数(逆元)

除法求模:
(a/b)%p=(ainv(b))%p=(a%pinv(b)%p)%p

逆元求解:
1、费马小定理(a与p互质才有a关于p的逆元)
因为a^(p-1)≡1(mod p)
两边同时除以a
a^(p-2)≡inv(a)(mod p)
inv(a)=a^(p-2)(mod p)
可以用快速幂求解
应用:
组合数求解:

ll fact[300000];
ll infact[300000];
ll mod=1e9+7;
long long fastpower(long long base,long long power,long long mod)
{
    ll ans=1%mod;
    while(power)
    {
        if(power&1)
        {
            ans=ans*base%mod;
        }
        base=base*base%mod;
        power>>=1;
    }
    return ans;
}
int main()
{
    fact[0]=1;
    infact[0]=1;
    for(ll i=1;i<=200000;i++)
    {
        fact[i]=fact[i-1]*i%mod;
        infact[i]=infact[i-1]*fastpower(i,mod-2,mod)%mod;
    }
    ll n,a,b;
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld%lld",&a,&b);
        printf("%lld\n",(fact[a]*infact[a-b]%mod)*infact[b]%mod);
    }
    return 0;
}

2、扩展欧几里得
ax+by=1
如果a、b互质,则有解,x即为a关于b的逆元,y就是b关于a的逆元
两边同时对a和b求模即可得到

#include<cstdio>
typedef long long LL;
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
    if (!b) {d = a, x = 1, y = 0;}
    else{
        ex_gcd(b, a % b, y, x, d);
        y -= x * (a / b);
    }
}
LL inv(LL t, LL p){//如果不存在,返回-1 
    LL d, x, y;
    ex_gcd(t, p, x, y, d);
    return d == 1 ? (x % p + p) % p : -1;
}
int main(){
    LL a, p;
    while(~scanf("%lld%lld", &a, &p)){
        printf("%lld\n", inv(a, p));
    }
}

3、当p是质数时有
inv(a)=(p-p/a)*inv(p%a)%p

证明:
设x = p % a,y = p / a
于是有 x + y * a = p
(x + y * a) % p = 0
移项得 x % p = (-y) * a % p
x * inv(a) % p = (-y) % p
inv(a) = (p - y) * inv(x) % p
于是 inv(a) = (p - p / a) * inv(p % a) % p

然后一直递归到1为止,因为1的逆元就是1

递归代码:

#include<cstdio>
typedef long long LL;
LL inv(LL t, LL p) {//求t关于p的逆元,注意:t要小于p,最好传参前先把t%p一下 
    return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p;
}
int main(){
    LL a, p;
    while(~scanf("%lld%lld", &a, &p)){
        printf("%lld\n", inv(a%p, p));
    }
}

递推代码:

#include<cstdio>
const int N = 200000 + 5;
const int MOD = (int)1e9 + 7;
int inv[N];
int init(){
    inv[1] = 1;
    for(int i = 2; i < N; i ++){
        inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
    }
}
int main(){
    init();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值