0902-求解逆元的三种方法

版权声明:虽然我只是个小蒟蒻但转载也请注明出处哦 https://blog.csdn.net/weixin_42557561/article/details/82315430

【逆元】

若gcd (a,m) = 1,且 ab = 1 (mod m),则称 b 为 a 模 m 意义下的逆元。显然,模意义下的除法可以用乘 逆元来代替。

【三种方法求解】

方法一:利用费马小定理,当 p 为质数,有 a^p−1=1 (mod p)

很容易发现a * a^p-2 = 1(mod p),那么 a 在模 p 意义下的逆元为 a^p-2

然后用快速幂计算即可

板子

int quickpower(int a,int b,int m){
    int ans=1;
    while(b){
        if(b&1) ans=1ll*ans*a%m;
        a=1ll*a*a%m;
        b>>=1;
    }
    return ans;
} 
inv[i]=quickpower(i,p-2,p);//i的逆元

例题

这道题用前缀积来处理,除的时候乘逆元,否则会出现精度问题,然后稍微注意一下边界情况即可

代码【我又和c++自带的函数重名了??无语】

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define inf 100009
#define p 9973
using namespace std;
int n;
int pmul[inf],ipmul[inf];
char st[inf];
int quickpower(int a,int b,int m){
    int ans=1;
    while(b){
        if(b&1) ans=1ll*ans*a%m;
        a=1ll*a*a%m;
        b>>=1;
    }
    return ans;
} 
int inv[inf];
int main(){
    while(scanf("%d",&n)!=EOF){
        int i,j,k;
        scanf("%s",st+1);
        int len=strlen(st+1);
        pmul[0]=1;
        ipmul[0]=1;
        for(i=1;i<=len;++i){
            pmul[i]=1ll*pmul[i-1]*(st[i]-28)%p;
            ipmul[i]=quickpower(pmul[i],p-2,p);
        }
        for(i=1;i<=n;++i){
            int a,b;
            scanf("%d%d",&a,&b);
            printf("%d\n",1ll*pmul[b]*ipmul[a-1]%p);
        }
    }
    return 0;
} 

方法二:扩展欧几里得算法详细戳这儿

把 ax ≡  1( mod b ) 变为 ax - by = 1 的形式,就可以啦,求出来的 x 就是 a 在模b意义下的逆元了

板子

void exgcd(int a,int b,int &x,int &y){
	if(b==0){	x=1;y=0;return;}
	ecgcd(b,a%b,y,x);
	y-=a/b*x;
}
exgcd(a,b,x,y);//a在模 b 意义下的逆元
x=(x%b+b)%b; 

最后这一步是保证 x 为模 b 意义下最小的正整数,学过扩展欧几里得的同学都知道一组合法解x,y,那么  x + t*b 也是合法的,x%b相当于是一直减 b,然后加上 b 是避免出现负数的情况

方法三 :线性筛(这个我不是很会,只能给板子,不好意思啦)

通过递推求1~n的逆元

我们可以通过inv[i]=inv[p%i]*(p-p/i)%p递推得到逆元。适用于n比较小的情况

板子

int inv[N];
void get_inverse(int n, int p) {
    inv[1] = 1;
    for (int i = 2; i <= n; ++i) {
        inv[i] = (p - p / i) * inv[p % i] % p;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_42557561/article/details/82315430