1. 程式人生 > >取模運算總結

取模運算總結

引入

  • 程式設計競賽有相當一部分題目的結果過於龐大,整數型別無法儲存,往往只要求輸出取模的結果。
  • 例如(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
    (2^2)1+30(2^1)1+30(2^0)*0=240+120+60=420
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的值時,