hdu 2669 Romantic (乘法逆元)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w144215160044/article/details/51505490

http://acm.hdu.edu.cn/showproblem.php?pid=2669


 什么叫乘法逆元?

    

    这里,我们称 x 是 a 关于 m 的乘法逆元

    这怎么求?可以等价于这样的表达式: a*x + m*y = 1

    看出什么来了吗?没错,当gcd(a , m) != 1 的时候是没有解的这也是 a*x + b*y = c 有解的充要条件: c % gcd(a , b) == 0

    接着乘法逆元讲,一般,我们能够找到无数组解满足条件,但是一般是让你求解出最小的那组解,怎么做?我们求解出来了一个特殊的解 x0 那么,我们用 x0 % m其实就得到了最小的解了。为什么?

可以这样思考:

    x 的通解不是 x0 + m*t 吗?

    那么,也就是说, a 关于 m 的逆元是一个关于 m 同余的,那么根据最小整数原理,一定存在一个最小的正整数,它是 a 关于m 的逆元,而最小的肯定是在(0 , m)之间的,而且只有一个,这就好解释了。

    可能有人注意到了,这里,我写通解的时候并不是 x0 + (m/gcd)*t ,但是想想一下就明白了,gcd = 1,所以写了跟没写是一样的,但是,由于问题的特殊性,有时候我们得到的特解 x0 是一个负数,还有的时候我们的 m 也是一个负数这怎么办?

    当 m 是负数的时候,我们取 m 的绝对值就行了,当 x0 是负数的时候,他模上 m 的结果仍然是负数(在计算机计算的结果上是这样的,虽然定义的时候不是这样的),这时候,我们仍然让 x0 对abs(m) 取模,然后结果再加上abs(m) 就行了,于是,我们不难写出下面的代码求解一个数 a 对于另一个数 m 的乘法逆元:


    

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <stack>
#include <vector>
#include <map>

using namespace std;

#define N 650
#define INF 0xfffffff
#define PI acos (-1.0)
#define EPS 1e-8
#define met(a, b) memset (a, b, sizeof (a))

typedef long long LL;

LL e_gcd (LL a, LL b, LL &x, LL &y)
{
    if (b==0)
    {
        x = 1;
        y = 0;
        return a;
    }

    LL ans = e_gcd (b, a%b, x, y);
    LL temp = x;
    x = y;
    y = temp-a/b*y;
    return ans;
}

LL cal (LL a, LL b)
{
    LL x, y;
    LL gcd = e_gcd (a, b, x, y);///扩展欧几里得
    if (1%gcd!=0) return -1;

    x *= 1/gcd;
    b = abs(b);

    LL ans = x%b;
    if (ans <= 0) ans += b;
    return ans;
}

int main ()
{
    LL a, b;

    while (scanf ("%I64d%I64d", &a, &b) != EOF)
    {
        LL x = cal(a, b);
        if (x==-1) puts ("sorry");
        else
        {
            LL y = (1-a*x)/b;
            printf ("%I64d %I64d\n", x, y);
        }
    }
    return 0;
}


感觉这样求最小逆元更简短:

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <stack>
#include <vector>
#include <map>

using namespace std;

#define N 1002000
#define INF 0xfffffff
#define PI acos (-1.0)
#define EPS 1e-8
#define met(a, b) memset (a, b, sizeof (a))

typedef long long LL;

void Ex_gcd (LL a, LL b, LL &gcd, LL &x, LL &y)
{
    if (!b)
    {
        x = 1;
        y = 0;
        gcd = a;
    }
    else
    {
        Ex_gcd (b, a%b, gcd, y, x);
        y -= a/b*x;
    }
}

int main ()
{
    LL a, b;
    while (scanf ("%I64d %I64d", &a, &b) != EOF)
    {
        LL x, y, gcd;
        Ex_gcd (a, b, gcd, x, y);

        if (1!=gcd)
        {
            puts ("sorry");
            continue;
        }

        x %= b;
        x = (x % (b/gcd) + b/gcd) % (b/gcd);

        printf ("%I64d %I64d\n", x, (1-a*x)/b);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/w144215160044/article/details/51505490