以A/B HDU1576这道题实践逆元的三种求法介绍

参考:http://blog.csdn.net/yukizzz/article/details/51105009
  在求解除法取模问题(a/b)%n时,我们可以转化为(a%(b∗n))/b,
但是如果b很大,则会出现爆精度问题,所以我们避免使用除法直接计算。
  可以使用逆元将除法转换为乘法:
  假设b存在乘法逆元,即与m互质(充要条件)。设c是b的逆元,即b∗c≡1(mod n),那么有a/b=(a/b)∗1=(a/b)∗b∗c=a∗c(mod n)
即,除以一个数取模等于乘以这个数的逆元取模。 
下面就HDU1576 A/B这道题来说三种方法的实现
1. 逆元求解一般利用扩欧。

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MD = 9973;
LL exgcd(LL a,LL b,LL &x,LL &y){
    if(b==0){
        x = 1;y =0; return a;
    }
    else{
        LL d = exgcd(b,a%b,x,y);
        LL t = x; x = y; y = t - a/b * y;       
        return d;
    }
}
LL inv(LL b,LL n){  //求b的逆元
    LL x,y;
    LL d = exgcd(b,n,x,y);
    if(d==1) return (x%n + n)%n;
    else return -1;
}
int main(){
    LL T,n ,b;
    cin >> T;
    for(LL i = 1;i<= T; i++){
        scanf("%lld%lld",&n,&b);
        LL y = inv(b,MD);
        printf("%lld\n",(n * y)%MD);
    }
    return 0;
}

2 当m为质数的时候直接使用费马小定理,m非质数使用欧拉函数。
利用欧拉定理b^phi(n)≡1(mod n)
b的逆元为b^-1 mod n=(b^(phi(n)-1)mod n+n)mod n

#include<iostream>
#include<cmath>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MD = 9973;
int quickMod(int x,int y){//快速幂
    int ans=1;
    x %= MD;
    while(y){
        if(y&1) ans = (ans * x) % MD;
        y = y/2;
        x = (x * x)%MD;
    }
    return ans;
} 
int eular(int x){ //求x的欧拉函数
    int ans = x;
    for(int i = 2,t = sqrt(x); i <= t; i++ ){
        if(x%i == 0){
            ans = ans / i * (i-1);
            while(x%i==0){  
                x = x / i; 
            }
        }
    }
    if(x > 1)  //对分解最后的那个质数进行处理 
        ans = ans / x * (x-1);
    return ans;
}
LL inv(LL b,LL n){//利用欧拉定理求逆元
    LL x,y;
    LL fin = eular(n);
    return quickMod(b,fin-1);
}
int main(){
    LL T,n ,b;
    cin >> T;
    for(LL i = 1;i<= T; i++)    {
        scanf("%lld%lld",&n,&b);
        LL y = inv(b,MD);
        printf("%lld\n",(n * y)%MD);
    }
    return 0;
}

3 当n为质数的时候,神奇的线性方法。 
但是题目数据中不能保证n为质数,因此不能使用此神奇方法,此方法详细解说见https://blog.csdn.net/xuechen_gemgirl/article/details/80332859

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

猜你喜欢

转载自blog.csdn.net/xuechen_gemgirl/article/details/77929143