取模運算總結
引入
- 程式設計競賽有相當一部分題目的結果過於龐大,整數型別無法儲存,往往只要求輸出取模的結果。
- 例如(a+b)%p,若a+b的結果我們儲存不了,再去取模,結果顯然不對,我們為了防止溢位,可以先分別對a取模,b取模,再求和,輸出的結果相同。
- a mod b表示a除以b的餘數。有下面的公式:
- (a + b) % p = (a%p + b%p) %p
- (a - b) % p = ((a%p - b%p) + p) %p
- (a * b) % p = (a%p)*(b%p) %p
- 注意對於除法取模,我們不能直接分別取模了,詳見逆元。
快速冪取模
typedef long long LL;
LL pow_mod(LL a,LL b,LL p){//快速冪取模
LL ans=1,base=a;
while(b>0){
if(b&1) //n%2==1
ans=ans*base%p;
base=base*base%p;
b>>=1;// b/=2
}
return ans;
}
快速乘法取模
- 當我們計算a*b%mod的時候,往往較大的數計算a*b會超出資料的範圍,這個時候使用快速乘法方法能解決上述問題.
- 快速乘法的原理是把數分解為多項式相加。舉個例子:
30*14 = 30*(1110)2 = 30*(2^3)1+30
typedef long long LL;
LL q_mul(LL a, LL b, LL p){//快速乘法取模
LL ans = 0;
while (b){
if(b&1LL) ans=(ans+a)%p;
//or ans=(ans+(b%2*a)%p)%p;
a = (a +a) % p;
b >>= 1;
}
return ans;
}
逆元/數論的倒數 - 對於倒數取模運算用逆元
逆元概念引入
(a + b) % p = (a%p + b%p) %p (對)
(a - b) % p = (a%p - b%p) %p (對)
(a * b) % p = (a%p * b%p) %p (對)
(a / b) % p = (a%p / b%p) %p (錯)
對於除法取模不能這樣,例如(100/50)%20 = 2 ≠ (100%20) / (50%20) %20 = 0
對於一些題目,我們必須在中間過程中進行求餘,否則數字太大,電腦存不下,那如果這個算式中出現除法,我們是不是對這個算式就無法計算了呢?
這時就需要逆元了
a*inv(a)=1
又對於a*b=1(mod p) b不一定是a的倒數,但是如果求餘,我們可以把b看作a的倒數,並稱b叫做a關於p的逆元。記b=inv(a)。
前提條件a和p互質,a才有關於p的逆元
那麼對於除法取模我們就好解決了。
(a / b) % p = (a * inv(a) ) % p = (a % p * inv(a) % p) % p
具體實現
費馬小定理
定理內容,如果p為質數,gcd(a,p)=1,那麼a^(p-1) ≡1 (mod p)
- a^(p-2) ≡1/a (mod p)
a^(p-2) ≡ inv(a) (mod p)
inv(a) = a^(p-2) (mod p)
- 時間複雜度為O(logn)
typedef long long LL;
LL fermat(LL a,LL p)//費馬求a關於b的逆元
{
return pow_mod(a,p-2,p);
}
擴充套件歐幾里德演算法
公式a∗x+b∗y=gcd(a,b) 。
若a,b互質且有解,則有a∗x+b∗y=1。
當我們要求a關於b的逆元,我們可以這樣看。
a*x % b + b*y % b = 1 % b
a*x % b = 1 % b
a*x = 1 (mod b)
可見,擴充套件歐幾里德演算法可以實現逆元。
typedef long long LL;
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){//擴充套件歐幾里德
if (!b) {d = a, x = 1, y = 0;}
else{
ex_gcd(b, a % b, y, x, d);
y -= x * (a / b);
}
}
LL inv(LL t, LL p){//如果不存在,返回-1
LL d, x, y;
ex_gcd(t, p, x, y, d);
return d == 1 ? (x % p + p) % p : -1;
}
例題
相關推薦
取模運算總結
引入 程式設計競賽有相當一部分題目的結果過於龐大,整數型別無法儲存,往往只要求輸出取模的結果。 例如(a+b)%p,若a+b的結果我們儲存不了,再去取模,結果顯然不對,我們為了防止溢位,可以先分別對
取模運算
add 結合 重要 nbsp left 但是 list padding 四則運算 腦子不好使,老是記不住(?_?),備忘一下。 模運算與基本四則運算有些相似,但是除法例外。其規則如下: (a + b) % p = (a % p + b % p) % p (a -
分數的乘法逆元和負數的取模運算
好的 分數 多少 研究 法則 表達 求余 推導 模運算 1.乘法逆元 A.定義 如果ax≡1 (mod p),且gcd(a,p)=1(a與p互質),則稱a關於模p的乘法逆元為x。 既然有ax≡1 (mod p),那麽有ax - py = 1,x是a關於模p的乘法逆元
Hdu 1395 2^x mod n = 1 取模運算
Problem Description Give a number n, find the minimum x(x>0) that satisfies 2^x mod n = 1. Input One positive integer on ea
取模運算和取餘運算
對於整型數a,b來說,取模運算或者求餘運算的方法都是: 1.求整數商: c = a/b; 2.計算模或者餘數: r = a - c*b. 求模運算和求餘運算在第一步不同: 取餘運算在取c的值時,向0方向舍入(fix()函式);而取模運算在計算c的值時,向-∞方向舍入(f
給定A, B兩個整數,不使用除法和取模運算,求A/B的商和餘數
第一種辦法: 從小到大遍歷 for(i = 2 to A - 1) if(i * B > A) 商 = i- 1, 餘 = A - (i -1) * B 第二種辦法 二分法,在[2, A]中查詢滿足的解 第三種辦法 以除數為初始測試值,以2的指數
關於取模運算(mod)和求餘(rem)運算
通常情況下取模運算(mod)和求餘(rem)運算被混為一談,因為在大多數的程式語言裡,都用’%’符號表示取模或者求餘運算。在這裡要提醒大家要十分注意當前環境下’%’運算子的具體意義,因為在有負數存在的情況下,兩者的結果是不一樣的。 對於整型數a,b來說,取模運算或者求餘運算的方法都是: 
【效能優化】取模運算:x%n,當n是偶數時,可以用x&(n-1)替代
#include <assert.h> void modulo_operation_opt() { int m = 100000; int n = 100000; double a
大數取模運算,快速冪取模運算
1.快速冪取模 快速冪取模就是在O(logn)內求出a^n mod b的值。演算法的原理是ab mod c=(a mod c)(b mod c)mod c long exp_mod(long a,long n,long b) { long t; if
Leetcode 29. Divide Two Integers--兩個32位整數相除,小數位截斷,不能使用乘法、除法、取模運算
Given two integers dividend and divisor, divide two integers without using multiplication, division and mod operator. Return the qu
遞迴,斐波那契數及其取模運算
一、遞迴 1、遞迴:即函式自己呼叫自己,函式在呼叫時會進行引數例項化,開闢棧空間。 2、遞迴可簡化程式碼的編寫。易讀。 3、遞迴必須設定遞迴出口,否則會出現死迴圈 4、遞迴過程需一直開闢棧空間,執行速度慢,效率低。且存在棧溢位問題 5、相比較,迭代(非
詳解負數取模運算
有人如果在python上使用%運算,肯定會遇到這樣的問題,就是它在負數上的結果和我們之前在C或JAVA上的結果不一樣。比如: -6 % 5這個運算,在python中的結果是4,但是在C/JAVA上的結果是-1 這是為什麼呢?wiki百科的解釋很好,英文好的可以
負數取模運算
最近在學習運算子時,遇到了負數取模(求餘數)的問題。對於正數取模很簡單,但複數取模時,不同的計算器卻有不同的答案。在網上看了一篇文件感覺總結的很詳盡和大家共享 源地址:https://ceeji.net/blog/mod-in-real/ 背景 最近在一道 Java 習題中
Java % (取模)運算
取模怎麼算 取模運算實際上是計算兩數相除以後的餘數。假設 q 是 a、b 相除產生的商(quotient),r 是相應的餘數(remainder),那麼在幾乎所有的計算系統中,都滿足: a = b x q + r,其中 |r|<|a|。
The mod(%) operation 負數取模運算詳解
Please indicate the source if you want to reprint: http://blog.csdn.net/gaoxiangnumber1 If a and d a
Java%(取模運算)詳解
一.Java的取模運算 1.實現演算法 public static double ramainder(double dividend, double dividor) { return dividend - dividend / divi
取模運算與取餘運算的區別
1.取模運算多見於計算機領域,取餘運算一般用於數學領域。 2.取模運算(取餘運算)計算步驟 ①求整數商 c=a/b ②求模(餘數)r=a-c*b 3.兩者不同點:取模運算c向負無窮遠處取整,取餘運算c
【帶除法的取模運算】hnoi2009有趣的數列
題目本身很簡單,有意識的人會打個表輕易地可以發現是個卡特蘭數列。 眾所周知卡特蘭數列的最普通的遞推式是O(N^2)的,資料規模是1000000,很顯然過不了,卡特蘭數列第i項還有另外一個公式就是C(n,2n)/(n+1),這個除法怎麼辦?我們所知的取模運算是不
java中的取模運算
Java中使用%作為取模運算的運算子,這與C、C++中是一致的。對於取模運算,大家並不陌生。取模運算實際上相當於我們小學的時候學過的求餘數。當時之所以引入餘數是因為還沒有講過小數的概念。所以進行除法運算時,除不盡的部分就被當做餘數來處理。比如5除以3等於1餘2。在當時
取模運算的性質
對於整型數a,b來說,取模運算或者求餘運算的方法都是: 1.求 整數商: c = a/b; 2.計算模或者餘數: r = a - c*b. 求模運算和求餘運算在第一步不同: 取餘運算在取c的值時,向0 方向舍入(fix()函式);而取模運算在計算c的值時,