求逆元算法


費馬小定理:若p是素數,a是正整數且不能被p整除,則ap-1 == 1(mod p)

費馬小定理的拓展:ap == a(mod p)

歐拉定理:對任意互素的a和n. 設Φ(n) 為小於n且與n互素的正整數的個數,有aΦ(n) == 1(mod n)

歐拉定理的拓展:aΦ(n)+1 == a(mod n)

求乘法逆元的作用:除以一個數 再取模時,可以將這個數乘以這個數的逆元 再取模(將除法轉化成乘法運算)

為什么要這樣等價:對於 (a/b)% mod 這個式子,是不可以等價為 ((a%mod) / (b%mod))%mod 的 (例如:a=3,b=2,mod=3),但是可以寫為(a*b-1)%mod,其中b-1表示b的逆元。這就是逆元的作用

引用計蒜客某題面:

什么是乘法逆元:a*x = 1(mod C),那么稱 x 為 a 對 C 的乘法逆元

e.g. a = 4,C = 7 則逆元 x = 2;

  4*2=1(mod 7)          12/4%7 = (12*2)%7 (除法換乘法)

用一道入門題來來學習三中模板:https://www.luogu.org/problem/P3811

 

模板一:

線性打表遞推法:(遞推公式:inv[i] = (p-p/i) * inv[p%i] % p )

這種方法最快,但是耗費的空間多

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <ctime>
 6 #include <climits>
 7 #include <utility>
 8 #include <deque>
 9 #include <queue>
10 #include <map>
11 #include <algorithm>
12 #include <functional>
13 using namespace std;
14 typedef long long ll;
15 
16 ll inv[3000006];
17 int main()
18 {
19     ll a, p;
20     while(~scanf("%lld %lld", &a, &p) )
21     {
22         memset(inv, 0, sizeof(inv));
23         inv[0] = 1;
24         inv[1] = 1;
25         for(ll i=2; i<=a; i++ )
26             inv[i] = (p-p/i)*inv[p%i]%p;
27         for(ll i=1; i<=a; i++ )
28             printf("%lld\n", inv[i]);
29     }
30     return 0;
31 }

模板二:

拓展歐幾里得算法

這道題我用這個方法TLE了,這個次慢

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <ctime>
 6 #include <climits>
 7 #include <utility>
 8 #include <deque>
 9 #include <queue>
10 #include <map>
11 #include <algorithm>
12 #include <functional>
13 using namespace std;
14 typedef long long ll;
15 
16 void exgcd(ll a, ll b, ll &x, ll &y)
17 {
18     if( b==0 )
19     {
20         x=1;
21         y=0;
22         return ;
23     }
24     exgcd(b, a%b, y, x);
25     y -= (a/b)*x;
26     return ;
27 }
28 
29 int main()
30 {
31     ll a, p;
32     ll x, y;
33     while( ~ scanf("%lld %lld", &a, &p) )
34     {
35         for(ll i=1; i<=a; i++ )
36         {
37             exgcd(i, p, x, y);
38             x = (x%p+p)%p;
39             printf("%lld\n", x);
40         }
41     }
42     return 0;
43 }

模板三:

費馬小定理算法:(快速冪(a,p-2,p)),前提是a p互質,這個也TLE了,這個最慢

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <string>
 5 #include <ctime>
 6 #include <climits>
 7 #include <utility>
 8 #include <deque>
 9 #include <queue>
10 #include <map>
11 #include <algorithm>
12 #include <functional>
13 using namespace std;
14 typedef long long ll;
15 
16 ll fpm(ll x, ll power, ll mod)
17 {
18     ll ans = 1;
19     for( ; power; power>>=1,(x*=x)%=mod )
20     if( power&1 )
21         (ans*=x)%=mod;
22     return ans;
23 }
24 
25 int main()
26 {
27     ll a, p;
28     ll x, y;
29     while( ~ scanf("%lld %lld", &a, &p) )
30     {
31         for(ll i=1; i<=a; i++ )
32         {
33             printf("%lld\n", fpm(i,p-2,p));
34         }
35     }
36     return 0;
37 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM