Modular Inverse ZOJ - 3609 (扩展欧几里得求逆元,不能用费马小定理)

Modular Inverse

ZOJ - 3609

The modular modular multiplicative inverse of an integer a modulo m is an integer x such that a-1x (mod m). This is equivalent to ax≡1 (mod m).


Input

There are multiple test cases. The first line of input is an integer T ≈ 2000 indicating the number of test cases.

Each test case contains two integers 0 < a ≤ 1000 and 0 < m ≤ 1000.

Output

For each test case, output the smallest positive x. If such x doesn't exist, output "Not Exist".

Sample Input
3
3 11
4 12
5 13
Sample Output
4
Not Exist
8

References


题意:求逆元

思路:比赛的时候看到求逆元我第一个想到的是费马小定理,用快速幂q_pow(a,m-2)求,但是由于对该定理不太熟悉,判断一个数不存在逆元时,以为如果a,m互素并且m是素数才行,费马小定理嘛,模必须是素数,但是后来一想,还有个欧拉函数,这样就不用必须是素数,求出欧拉函数来,只要a,m互素,对于任意a都可求其逆元,但是这样写提交就超时了,虽然知道还有一个扩展欧几里得可以求逆元,但是当时感觉都差不多,而且扩展欧几里得不太会写,就没做出来。然后结束后搜题解,发现所有的博客都是用扩展欧几里得写的,搜了下两种方法的区别,两种方法的确有一些区别而且扩展欧几里得的效率稍微比费马小定理高一些:

原话

扩展欧几里得算法效率较高,常数较小,时间复杂度为O(ln n)

费马小定理算法复杂度为O(log2 n) 在几次测试中,常数似乎较上种方法大

大概这题就是卡数据吧。

最后要求最小正整数,如果答案小于等于0,需要+模,千万不要加完再模,如果答案是0加模再模那不和没一样嘛。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int e_gcd(int a,int b,int &x,int &y){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    int ans = e_gcd(b,a%b,y,x);
    y -= a / b * x;
    return ans;
}

int main(){
    int t;
    while(~scanf("%d",&t)){
        while(t--){
        int a,m;
        int x,y;
        scanf("%d%d",&a,&m);
        int gcd = e_gcd(a,m,x,y);
        if(gcd != 1){
            printf("Not Exist\n");
            continue;
        }
        int ans = x;
        ans = ans % m;
        if(ans <= 0) ans = ans + m;//这里千万不要再模m,万一答案是0,模完还是0
        printf("%d\n",ans);
    }
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/80038790