求逆元方法总结

在MOD的情况下,  (a*b/c ) %MOD  不能直接 / c 来求,需要找到一个数 inv 使得  inv * c % MOD = 1 。 这样 (a*b / c) % MOD  = (a * b * inv) % MOD;

性质: 逆元是积性函数   存在  a*b = c ,那么  inv[c] = inv[a] * inv[b] % MOD;

1、  循环找解的方法

long long circleRun(long long n){
	for(long long i = 1;i < MOD;i++)
		if(i * n % MOD == 1)
			return i;
	return -1;
}
long long n;
int main(){

	while(cin >> n){
		cout << n << " 's inv is "<<endl;
		cout << circleRun(n) << endl;
	}
	return 0;
}

2、费马小定理的解法  MOD 是质数才能用

利用   a ^ (p-1) % MOD === 1 , 那么它的逆元就是     a ^ (p-2)

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<cmath>
using namespace std;

const int MOD = 1e9+7;

long long quickpow(long long base,long long n){
	long long ans = 1;
	while(n){
		if(n%2 == 1) ans = ans * base % MOD;
		n /= 2;
		base = base * base % MOD;
	}
	return ans;
}
long long n;
int main(){

	while(cin >> n){
		cout << n << " 's inv is "<<endl;
		//cout << circleRun(n) << endl;
		cout << " a ^ (p-2) % MOD "<< endl;
		cout << quickpow(n, MOD-2) << endl;

	}
	return 0;
}

3、利用欧几里德扩展来求 ,

欧几里德扩展 是用来解决  ax + by = gcd(a,b)这样的等式。

这时候取  b = MOD, 你可以写成这样  ax = gcd(a,b) - by

推导出 a*x % MOD = gcd(a,b) %MOD

所以只要  gcd(a,b) % MOD === 1时,就可以使用这条来求a的逆元

但用exgcd求得时候,inv可能是负数, 还需要进行如下操作

inv = (inv % MOD + MOD) % MOD;
long long exGcd(long long a, long long b, long long &x0, long long &y0) // a*x0 + b*y0 = gcd(a,b)
{
    if(b==0)
    {
      x0 = 1;
      y0 = 0;
      return a;
    }
    long long r = exGcd(b, a % b, x0, y0);
    long long t = x0;
	x0 = y0;
	y0 = t - a / b * y0;
	return r;
}

long long n;
int main(){

	while(cin >> n){
		cout << n << " 's inv is "<<endl;
		//cout << circleRun(n) << endl;
		cout << " a ^ (p-2) % MOD "<< endl;
		cout << quickpow(n, MOD-2) << endl;

		cout << " ax + by = gcd(a,b) " << endl;
		long long inv,y0;
		exGcd(n ,MOD,inv,y0);
		inv = (inv % MOD + MOD) % MOD;
		cout << inv << endl;
	}
	return 0;
}

4、利用某神奇推导。。 O(n)求出 1---- n 的所有逆元。

预处理1-n关于p的逆元:(n < p) , 因为 逆元是积性函数,所以只要 p > n 成立即可,而不需要p必须为素数

假设已经预处理了1-i-1的逆元,j的逆元设为F[j]

令p = x * i –y ( 0 < y < i)

X* i = y (mod p)

X* F[y] * i = y * F[y] = 1(mod p)

所以i的逆元是F[i] = X* F[y]

这样就可以O(n)的时间预处理了。

参考链接

代码实现

const int N = 100005;
long long _inv[N];
void pre() {
	_inv[0] = _inv[1] = 1;
	for (int i = 2; i < N; i++) {
		_inv[i] = ((MOD - MOD / i) * _inv[MOD % i]) % MOD;
	}
}
long long n;
int main(){
        pre();
	while(cin >> n){
		cout << _inv[n] << endl;
	}
        return 0;
}

4、 利用逆元函数是完全积性函数的性质

求所有质数的逆元即可,预处理复杂度是O(n / logn * logn) = O(n)

这种写法可以用 exgcd 来实现素数的logn 求逆,因为此时  a = p ,  MOD无论取何值(p除外)  ,  都有  gcd(p ,mod) = 1,适合通用情况。

之后再采取质因数分解的方法,即可对任意一个 n 以 logn速度求出其逆元

不过。。ACM竞赛如果为了求逆写这么长的代码貌似不太现实。

时间: 2024-10-31 15:17:56

求逆元方法总结的相关文章

(转载)各种求逆元方法总结

在MOD的情况下,  (a*b/c ) %MOD  不能直接 / c 来求,需要找到一个数 inv 使得  inv * c % MOD = 1 . 这样 (a*b / c) % MOD  = (a * b * inv) % MOD; 性质: 逆元是积性函数   存在  a*b = c ,那么  inv[c] = inv[a] * inv[b] % MOD; 1.  循环找解的方法 long long circleRun(long long n){ for(long long i = 1;i <

(数论)简单总结求逆元的几种方法

逆元(Inverse element),如a?b≡1(modp),那么a,b互为模p意义下的逆元,则p|(a/c-b*c)(即a/c与b*c同余). 常用的求逆元方法有 1.费马小定理 若p为素数,且gcd(a,p)=1,则a^(p-1)≡1(mod p),即a*a^(p-2)≡1(mod p),故a的逆元为a^p-2. 2.拓展欧几里德算法(递推再回溯) 当gcd(A,B)|C时,可求二元一次方程Ax+By=C的整数通解. 3.逆元线性筛 递推公式:inv[i]=inv[p % i] * (p

hdu 1576 求逆元

题意:给出n=A mod 9973和B,求(A/B) mod 9973 昨天用扩展欧几里得做过这题,其实用逆元也可以做. 逆元的定义:例如a*b≡1 (mod m),则b就是a关于m的逆元. 求逆元方法也很简单,用扩展欧几里得解这个方程即可. 逆元性质:若a是b的逆元,则(x/a)mod p=(x*b)mod p 对于本题呢?设B的逆元为x, 那么有(A/B) mod 9973=((A mod 9973)*(x mod 9973))mod 9973 Reference:  http://blog

除法求模中求逆元的两种方法

今天下午还是有点闲的,不想刷题,不想补题,突然想起昨天的training 3里I题涉及到除法取模的问题,就来总结一下 首先对于模运算来说,是没有对于除法的取模的(即没有(a/b)%mod==a%mod/b%mod),但是在很多题目中都涉及到除法取模,所以就必须要了解或者掌握,对于除法取模以(a/b)%mod来说,我们首先需要得到b的逆元,根据逆元的定理 对于正整数和,如果有,那么把这个同余方程中的最小正整数解叫做模的逆元. 然后就是求逆元的两种方法. 第一种方法就是比较普遍的,也是挺基础的,就是

几种求逆元的方法

一, 扩展欧几里得 1 void exgcd(int a,int b,int &x,int &y) 2 { 3 if(b==0) 4 { 5 x=1;y=0;return; 6 } 7 exgcd(b,a%b,x,y); 8 swap(x,y); 9 y=y-a/b*x; 10 } 11 //a在%b意义下的逆元 12 //a*x+b*y=1的解->要求a与b互质才有解 二,费马小定理求逆元 要求:模数p为质数 费马小定理:a^(p-1)=1(mod p) 那么a^(p-2)=a^-

【BZOJ-4522】密钥破解 数论 + 模拟 ( Pollard_Rho分解 + Exgcd求逆元 + 快速幂 + 快速乘)

4522: [Cqoi2016]密钥破解 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 290  Solved: 148[Submit][Status][Discuss] Description 一种非对称加密算法的密钥生成过程如下: 1.任选两个不同的质数p,q 2.计算N=pq,r=(p−1)(q−1) 3.选取小于r,且与r互质的整数e 4.计算整数d,使得ed≡1KQ/r 5.二元组(N,e)称为公钥,二元组(N,d)称为私钥 当需要加密

线性求逆元

简介 逆元,简单的来说就是a?b≡1(modp),那么b就是a关于p的逆元. 正常的来说用扩展欧几里得来做.复杂度不是线性的. 但是如果所有的i≤p,有一个线性求逆元的方法. 正常的来说 方法 因为i≤p,所以考虑用i来表示p,并要求表示出来的所有数都能用p和i表示. 设p=ki+b,k=?pi?,l=pmodi 那么ki+b≡0(modp) 因为要求的是i?1,所以需要把i?1独立起来,所以我们等式两边同时乘以i?1b?1 那么式子就可以变成kb?1+i?1≡0 然后把可以求得i的逆元的数放到

HDU 5768Lucky7(多校第四场)容斥+中国剩余定理(扩展欧几里德求逆元的)+快速乘法

地址:http://acm.hdu.edu.cn/showproblem.php?pid=5768 Lucky7 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 754    Accepted Submission(s): 279 Problem Description When ?? was born, seven crows flew

线性求逆元推导

本篇介绍线性求逆元的推导过程 ·对于一个质数\(P\),我们需要求出\(1-N\)在\(mod\ P\)意义下的逆元,如何使用线性的方法求其逆元呢? ·首先,我们设\(t=P/i,k=P%i\); ·对于\(i*t+k≡0 \pmod{P}\),我们可以做出如下推导: ·等式两边同时除以\(i*k\),我们可以得到新式子\(\frac{t}{k}+\frac{1}{i}≡0 \pmod{P}\); ·从而得到:\(\frac{P}{i}*inv[P\%i]+inv[i]≡0 \pmod{P}\)