乘法逆元

乘法逆元

定义:对于任意的n>1,如果gcd(a,n)=1,那么方程ax=1(modn)对模n有唯一的解。

乘法逆元实例,比如计算(A/B)%K

其中K为常数,

当A特别大的时候侧需要乘法逆元。

定义:
满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元。

为什么要有乘法逆元呢?
当我们要求(a/b) mod p的值,且a很大,无法直接求得a/b的值时,我们就要用到乘法逆元。
我们可以通过求b关于p的乘法逆元k,将a乘上k再模p,即(a*k) mod p。其结果与(a/b) mod p等价。

证:(其实很简单。。。)
根据b*k≡1 (mod p)有b*k=p*x+1。
k=(p*x+1)/b。
把k代入(a*k) mod p,得:
(a*(p*x+1)/b) mod p
=((a*p*x)/b+a/b) mod p
=[((a*p*x)/b) mod p +(a/b)] mod p
=[(p*(a*x)/b) mod p +(a/b)] mod p
//p*[(a*x)/b] mod p=0
所以原式等于:(a/b) mod p


例题,

B - A/B

Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status

Description

要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
 

Input

数据的第一行是一个T,表示有T组数据。
每组数据有两个数n(0 <= n < 9973)和B(1 <= B <= 10^9)。
 

Output

对应每组数据输出(A/B)%9973。
 

Sample Input

 
      
2 1000 53 87 123456789
 

Sample Output

 
      
7922 6060


void sovle()
{
 long long a = 9973, b;
 long long x, y;
 long long c = 1;
 long long T_case = 0;
 cin >> T_case;
 long long exgcd(long long a, long long b, long long &x, long long &y);
 for (long long i = 0; i < T_case; i++)
 {
  long long   n;
  cin >> n >> b;
  long long d = exgcd(b, -a, x, y);
  if (abs(d) == 1)
  {
        long long k = n / d;
   //long long p0 = x*k;
   //long long q0 = y*k;


     x = x*k;
   
   long long t = 0;
   //if (x<0)
   //{
   // t = -x;
   // t = t%k;
   // x = k - t;     //或者不用t变量  直接x=k-(-x)%k;或者用while(x<0){x+=k/1;},不过不推荐使用,因为可能会超时!最好用 x=(x%k+k)%k即可,if语句也不用了; 
   //}
   long long result;

   result = x%a;
   if (result < 0)
   {
    result = a + result;
   }

   printf("%lld\n", x);
   printf("%lld",result);

   /*for (long long t = 1; t < 10; t++)
   {
   cout << p0 + (b / d)*t << " " << q0 - (a / d)*t << endl;
   }*/

  }
  else
  {
   cout << "sorry" << endl;

  }
 }
}

long long exgcd(long long a, long long b, long long &x, long long &y)//求解方程特解的过程中同时进行了求最大公约数的计算。//扩展欧几里得算法求解模线性方程
{

 long long r;
 if (b == 0)
 {
  x = 1;
  y = 0;
  return a;
 }
 else
 {
  r = exgcd(b, a%b, x, y);
  long long t = x;
  x = y;
  y = t - (a / b)*y;

 }

 return r;


}
void Eratosthenes()
{
 int vis[1000];
 int n;
 cin >> n;
 memset(vis, 0, sizeof(vis));
 for (int i = 2; i <=n ; i++)
 {
  for (int j = i * 2; j <= n; j += i)
   vis[j] = 1;
 }
 for (int i = 0; i <= n; i++)
 {
  if (vis[i] == 0)
   cout << i << endl;
 }
}

总结:利用乘法逆元的求法,及其代换的相关公式,注意其中求得的余数有可能是负数此时就应当把辅助按照运算规律转换为正数。加油加油!!

你可能感兴趣的:(算法分析与数学)