1. 程式人生 > >逆元的三種解法(附詳細證明)

逆元的三種解法(附詳細證明)

友情提示:

Latex載入稍慢,請耐心等待

什麼是逆元?

若$x$滿足

$a*x\equiv 1(\mod p)$

我們稱$x$是$a$在$\mod p$意義下的逆元

逆元的基本解法

https://loj.ac/problem/110

1.快速冪

當p為素數

根據費馬小定理

$a^{(p-1)}\equiv 1(mod p)$

${\color{Green}a*a^{(p-2)}\equiv 1(mod p) }$

帶入快速冪就好啦

時間複雜度:$O(log_2^p)$

 1 #include<cstdio>
 2 #define LL long long 
 3
using namespace std; 4 const LL MAXN=200000001; 5 LL n,mod; 6 LL fastpow(LL val,LL p) 7 { 8 LL base=1; 9 while(p) 10 { 11 if(p&1) base=(base*val)%mod; 12 val=(val*val)%mod; 13 p>>=1; 14 } 15 return base; 16 } 17 int main() 18 {
19 scanf("%lld%lld",&n,&mod); 20 for(LL i=1;i<=n;i++) 21 printf("%lld\n",fastpow(i,mod-2)%mod); 22 return 0; 23 }

2.擴充套件歐幾里得

對於$a*x\equiv 1(mod p)$

他的另一種寫法為

$a*x+p*y=1$(想一想,為什麼)

擴充套件歐幾里得,帶入求解

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4
using namespace std; 5 int n,mod; 6 inline int read() 7 { 8 char c=getchar();int flag=1,x=0; 9 while(c<'0'||c>'9') {if(c=='-') flag=-1;c=getchar();} 10 while(c>='0'&&c<='9') x=x*10+c-48,c=getchar(); return x*flag; 11 } 12 int x,y; 13 int gcd(int a,int b) 14 { 15 return b==0?a:gcd(b,a%b); 16 } 17 int exgcd(int a,int b,int &x,int &y) 18 { 19 if(b==0) 20 { 21 x=1,y=0; 22 return a; 23 } 24 int r=exgcd(b,a%b,x,y); 25 int tmp=x;x=y;y=tmp-(a/b)*y; 26 return r; 27 } 28 int main() 29 { 30 n=read(),mod=read(); 31 for(int i=1;i<=n;i++) 32 { 33 int g=exgcd(i,mod,x,y); 34 while(x<0) x+=mod; 35 printf("%d\n",x); 36 } 37 return 0; 38 }

時間複雜度:$O(log_2^n)$

 3.遞推

前兩種方法常用來求單個逆元

對於逆元的需要量比較大的時候,我們可以使用遞推的方法來求逆元

前提條件:$P$為素數

推導過程

設$t=P/i$
$k=P \mod i$

顯然有

$t*i+k \equiv  0 (\mod P)$

$k \equiv -t*i(\mod P)$

兩側同除$i*k$,把$t$和$k$帶入

$inv[i] \equiv -p/i*inv[p \mod i] (\mod p)$

這裡需要注意一個事情,

對於 $a\mod p$當$a<0$時,

應為$(a+p) \mod p$

這樣就可以把原式的$\mod p$消掉,得

$inv[i]=P-P/i*inv[P\mod i]$

這樣就可以進行線性的遞推啦

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #define LL unsigned long long 
 6 using namespace std;
 7 const LL MAXN=200000001;
 8 inline LL read()
 9 {
10     char c=getchar();LL flag=1,x=0;
11     while(c<'0'||c>'9')    {if(c=='-')    flag=-1;c=getchar();}
12     while(c>='0'&&c<='9')    x=x*10+c-48,c=getchar();    return x*flag;
13 }
14 LL inv[MAXN];
15 LL n,p;
16 int main()
17 {
18     n=read(),p=read();
19     inv[1]=1;
20     printf("1\n");
21     for(int i=2;i<=n;i++)
22     {
23         inv[i]=(p-p/i)*inv[p%i]%p;
24         printf("%d\n",inv[i]);
25     }
26     return 0;
27 }

時間複雜度:$O(n)$

總結

在求多個數的逆元的時候,推薦使用遞推演算法

在求單個數的逆元的時候,推薦使用擴充套件歐幾里得演算法

因為擴充套件歐幾里得演算法不受模數的限制,而且自測執行效率比快速冪高不少

相關推薦

解法(詳細證明)

友情提示: Latex載入稍慢,請耐心等待 什麼是逆元? 若$x$滿足 $a*x\equiv 1(\mod p)$ 我們稱$x$是$a$在$\mod p$意義下的逆元 逆元的基本解法 https://loj.ac/problem/110 1.快速冪 當p為素數 根據費馬小定理 $

load傳遞引數的方式(步驟詳細程式碼,要是你們看不懂我就放棄程式設計)

方式一:直接獲取上個頁面的資料; 這種方式主要依賴load這個方法的原理,這個其實就是一個本地ajax請求,所以前後兩個頁面是互通的,其資料是可以直接拿到的。例項如下: a頁面的程式碼: <script> var adata = "12"; $("#d

codevs 2924 數獨挑戰 x(做法+超詳細註釋~)

是否 初始化 cst next using 最大 pos 描述 name 2924 數獨挑戰 時間限制: 1 s 空間限制: 1000 KB 題目等級 : 鉆石 Diamond

動態規劃 跳臺階問題的解法

for 發現 規劃 == you new 我們 tair bing You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 o

LeetCode 647. Palindromic Substrings的解法

轉載地址 https://www.cnblogs.com/AlvinZH/p/8527668.html#_label5 題目詳情 給定一個字串,你的任務是計算這個字串中有多少個迴文子串。 具有不同開始位置或結束位置的子串,即使是由相同的字元組成,也會被計為是不

LeetCode 923. 數之和的多種可能(機智題 解法

題意: 給定一個整數陣列 A,以及一個整數 target 作為目標值,返回滿足 i < j < k 且 A[i] + A[j] + A[k] == target 的元組 i, j, k 的數量。

spark的模式的詳細執行過程(基於standalone與基於yarn)

一、Standalone模式 1、使用SparkSubmit提交任務的時候(包括Eclipse或者其它開發工具使用new SparkConf()來執行任務的時候),Driver執行在Client;使用SparkShell提交的任務的時候,Driver是執行在Master上 2、使用SparkSu

排列硬幣 arrange coins 解法詳解

* 排列硬幣 * https://leetcode-cn.com/problems/arranging-coins/description/ * 你總共有 n 枚硬幣,你需要將它們擺成一個階梯形狀,第

EF程式設計方式詳細圖文教程(C#+EF)之Database First

Entity Framework4.1之前EF支援“Database First”和“Model First”程式設計方式,從EF4.1開始EF開始支援支援“Code First”程式設計方式,今天簡單看一下EF三種程式設計方式。 開始介紹這三種EF操作方式之前,首先在

LeetCode演算法題-First Bad Version(Java實現-解法

這是悅樂書的第200次更新,第210篇原創 01 看題和準備 今天介紹的是LeetCode演算法題中Easy級別的第66題(順位題號是278)。您是產品經理,目前領導團隊開發新產品。不幸的是,您產品的最新版本未通過質量檢查。由於每個版本都是基於以前的版本開發的,因此壞版本之後的所有版本也是壞的。 假設

斐波那契數列的解法及時間複雜度

斐波那契數列: f(n)=f(n-1)+f(n-2)(n>2) f(0)=1;f(1)=1; 即有名的兔子繁衍問題 在本篇文章我將會給出三種解法

LeetCode演算法題-Move Zeroes(Java實現-解法

這是悅樂書的第201次更新,第211篇原創 01 看題和準備 今天介紹的是LeetCode演算法題中Easy級別的第67題(順位題號是283)。給定一個數組nums,寫一個函式將所有0移動到它的末尾,同時保持非零元素的相對順序。例如: 輸入:[0,1,0,3,12] 輸出:[1,3,12,0,0]

Input array is sorted解法對比

本文對比LeetCode 167. Two Sum II - Input array is sorted三種不同的解法並進行優化,拋磚引玉,望各位大佬指教。 題目: Given an array of integers that is already sorted in

JAVA:定時器的方法(詳細註解)

第一種:         建立一個thread,然後讓它在while迴圈裡一直執行著,通過sleep方法來達到定時任務的效果,程式碼如下: public class Task1 { public static void main(String[] args) { /

最長單調遞增子序列的解法

問題描述:找出由n個數組成的序列的最長單調遞增子序列 解法一:轉化成LCS問題求解,時間複雜度為O(n*n). 思路:原序列為A,把A按升序排序得到序列B,求出A,B序列的最長公共子序列,即為A的最長

青蛙爬臺階問題的解法@python

本文系原創,轉載請註明出處 題意描述 You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2

演算法導論第版第六章 合併K個有序連結串列的解法(最小堆法和分治遞迴法)

題目要求是將k個有序連結串列合併為一個連結串列,時間複雜度限定為O(nlogk)。下面給出應用最小堆方法的兩個程式,最後再貼上利用分治遞迴法的程式碼,雖然時間複雜度不及堆方法,但思路相對簡單好理解。 (1)最小堆方法1 用一個大小為K的最小堆(用優先佇列+自定義降序實現)(

n皇后問題的解法

      N皇后問題是一個經典的問題,在一個N*N的棋盤上放置N個皇后,每行一個並使其不能互相攻擊(同一行、同一列、同一斜線上的皇后都會自動攻擊)。 n皇后問題不算是陳詞濫調,也是老生常談了,作為回溯的經典案例,有遞迴和非遞迴兩種實現方式,同時,除了回溯演算法,最近我在網

統計一個整數的二進位制中1的個數的解法

一、每一位與0x1進行與運算 int countOne(int num)   {       int count = 0;       while ( num )       {         

【劍指offer】陣列中出現次數超過陣列長度一半的數字(解法

題目描述 陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。例如輸入一個長度為9的陣列{1,2,3,2,2,2,5,4,2}。由於數字2在陣列中出現了5次,超過陣列長度的一半,因此輸出2。如果不存在則輸出0。 如果使用時間複雜度為O(n),可以構建