快速冪運算(入門完整版)
結合律 | ((a+b) mod p + c)mod p = (a + (b+c) mod p) mod p ((a*b) mod p * c)mod p = (a * (b*c) mod p) mod p |
交換律 | (a + b) mod p = (b+a) mod p (a × b) mod p = (b × a) mod p |
分配律 | ((a +b)mod p × c) mod p = ((a × c) mod p + (b × c) mod p) mod p (a×b) mod c=(a mod c * b mod c) mod c (a+b) mod c=(a mod c+ b mod c) mod c (a-b) mod c=(a mod c- b mod c) mod c |
我們先從簡單的例子入手:求x^n % mod 。
演算法1.首先直接地來設計這個演算法:
int mod1(int x,int n,int mod)
{
int ans=1;
for(int i=1;i<=n;i++)
{
ans*=x;
}
return ans%mod;
}
這個演算法的時間複雜度體現在for迴圈中,為O(n).這個演算法存在著明顯的問題,如果x和n過大,很容易就會溢位。
那麼,我們先來看看第一個改進方案:在講這個方案之前,要先有這樣一個公式:
(a*b)%c = ((a%c)*b)%c
這個公式大家在離散數學或者數論當中應該學過,即積的取餘等於取餘的積的取餘。
證明了以上的公式以後,我們可以先讓a關於c取餘,這樣可以大大減少a的大小,溢位的可能性會大大減小
於是上面的程式進行了改進:
**演算法2: *
int mod2(int x,int n,int mod)
{
x=x%mod;///這裡就是改進的那一步
int ans=1;
for(int i=1;i<=n;i++)
{
ans*=x;
}
return ans%mod;
}
聰明的讀者應該可以想到,既然某個因子取餘之後相乘再取餘保持餘數不變,那麼新算得的ans也可以進行取餘,所以得到比較良好的改進版本。
演算法3:
int mod3(int x,int n,int mod) { x=x%mod;///這裡就是改進的那一步 int ans=1; for(int i=1;i<=n;i++) { ans=(ans*x)%mod;///又一次改進 } return ans%mod; }
這個演算法在時間複雜度上沒有改進,仍為O(n),不過已經好很多的,但是在mod過大的條件下,還是很有可能超時,所以,我們推出以下的快速冪演算法。
快速冪演算法依賴於以下明顯的公式,我就不證明了。
a^b mod c=(a^2)^(b/2) mod c (b為偶數);
a^b mod c=((a^2)^(b div 2)*a) mod c (b為奇數)
有了上述兩個公式後,我們可以得出以下的結論:
1.如果b是偶數,我們可以記k = a^2 mod c,那麼求(k)^b/2 mod c就可以了。
2.如果b是奇數,我們也可以記k = a^2 mod c,那麼求
((k)^b/2 mod c × a ) mod c =((k)^b/2 mod c × a) mod c 就可以了。
那麼我們可以得到以下演算法:
演算法4:
int mod4(int x,int n,int mod)
{
int ans = 1;
x = x % mod;
if(n%2==1)
ans = (ans * x) % mod; //如果是奇數,要多求一步,可以提前算到ans中
int k = (x*x) % mod; //我們取a2而不是a
for(int i = 1; i<=n/2; i++)
{
ans = (ans * k) % mod;
}
ans = ans % mod;
return ans;
}
我們可以看到,我們把時間複雜度變成了O(n/2).當然,這樣子治標不治本。但我們可以看到,當我們令k = (x × x) % mod 時,狀態已經發生了變化,我們所要求的最終結果即為(k)^(n/2 ) % mod 而不是原來的(x^n) % mod ,所以我們發現這個過程是可以迭代下去的。當然,對於奇數的情形會多出一項x % mod ,所以為了完成迭代,當n是奇數時,我們通過
ans = (ans * x) % mod;來彌補多出來的這一項,此時剩餘的部分就可以進行迭代了。
形如上式的迭代下去後,當b=0時,所有的因子都已經相乘,演算法結束。於是便可以在O(log b)的時間內完成了。於是,有了最終的演算法:快速冪演算法。
演算法5:快速冪演算法
int mod5(int x,int n,int mod)
{
int ans = 1;
x = x % mod;
while(n>0)
{
if(n % 2 == 1)
ans = (ans * x) % mod;
n = n/2;
x = (x * x) % mod;
}
return ans;
}
本演算法的時間複雜度為O(logn),能在幾乎所有的程式設計(競賽)過程中通過,是目前最常用的演算法之一。
以下內容僅供參考:
擴充套件:有關於快速冪的演算法的推導,還可以從另一個角度來想。
求解這個問題,我們也可以從進位制轉換來考慮:
將10進位制的b轉化成2進位制的表示式:
那麼,實際上,.例如:x^22=x^16 × x^4 × x^2;
(而22轉換為二進位制數是10110)
所以,注意此處的要麼為0,要麼為1,如果某一項,那麼這一項就是1,這個對應了上面演算法過程中b是偶數的情況,為1對應了b是奇數的情況[不要搞反了,讀者自己好好分析,可以聯絡10進位制轉2進位制的方法],我們從依次乘到。對於每一項的計算,計算後一項的結果時用前一項的結果的平方取餘。對於要求的結果而言,為時ans不用把它乘起來,[因為這一項值為1],為1項時要乘以此項再取餘。
當然,這裡對於n的控制也可以用二進位制的思想來比較好理解
演算法6:
ll mod_pow(ll x,ll n,ll mod)
{
ll res=1;
while(n>0)
{
if(n&1)
res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
還可以遞迴來實現演算法6:
ll mod_pow1(ll x,ll n,ll mod)
{
if(n==0) return 1;
ll res=mod_pow1(x*x%mod,n/2,mod);
if(n&1) res=res*x%mod;
return res;
}
相關推薦
快速冪運算(入門完整版)
結合律 ((a+b) mod p + c)mod p = (a + (b+c) mod p) mod p ((a*b) mod p * c)mod p = (a * (b*c) mod p) mod p 交換律 (a + b) mod p = (b+a) mod p (a × b
【Java】Swing+IO流實現一個簡單的文件加密程序(較完整版)
move 初始 baidu images 文件選擇器 while login 一個 ktr 留著參考 beans package com.my.bean; import java.io.Serializable; public class
BZOJ 3992: [SDOI2015]序列統計 快速冪+NTT(離散對數下)
不同 led gre lan cnblogs 至少 inf tro 程序編寫 3992: [SDOI2015]序列統計 Description 小C有一個集合S,裏面的元素都是小於M的非負整數。他用程序編寫了一個數列生成器,可以生成一個長度為N的數列,數列中
zabbix監控模板修改及調優(不完整版)
之前 evel proc 表達式 至少 dir 手動 最新 slave 簡介監控一直在不同的層面為我們的運維工作發揮著重要的作用:網絡層監控,及時發現網絡間的訪問質量(如我們之前介紹的全國maps網絡監控);服務器監控,了解服務器各項性能參數(如常見的zabbix、cact
Spring整合Quartz框架實現定時任務跑批(Maven完整版)
觸發器 delay cut www 方法 lin job 定時任務 任務調度 Quartz 介紹Quartz is a full-featured, open source job scheduling service that can be integrated with
3D-HEVC/HTM測試序列下載地址(官方完整版)
轉載地址: http://blog.csdn.net/yangxiao_xiang/article/details/10552633,感謝博主。 最新3DV通用測試條件Common TestConditions of 3DV Core Experiments(JCT3V-E
《C++Primer》第 5 版第 2 章筆記(未完整版)
第 2 章 變數和基本型別 1. 基本內建型別分為 算術型別和空型別 2. 算術型別分為 整型 和 浮點型 3. 整型分為 int、字元、布林型別 4. char 1位元組 short 2位元組 int和long 4位元組 long long 8位元組 fl
Zookeeper叢集設計與安裝部署(最完整版)
首先準備好3個節點分別為hadoop01、hadoop02、hadoop03,接下來帶著大家一起搭建最小規模的Zookeeper分散式叢集。 1.叢集規劃 1.1主機規劃 使用準備的3個節點,搭建一個最小規模的Zookeeper分散式叢集。 1.2軟體規劃
索引規約(非完整版)
模糊查詢: 前模糊:LIKE '%XXX' -- 查詢尾部字串相同的 後模糊:LIKE 'YYY%' -- 查詢首部字串相同的 全模糊:LIKE '%ZZZ%' -- 查詢中間字串相同的 頁面搜尋禁止左模糊或者全模糊。因為索引檔案具有B-tree的最左字首匹配特性。
C#WinForm窗體事件執行次序(較完整版)
一、以下是網路上可搜尋到的次序 當 Windows Form 應用程式啟動時,會以下列順序引發主要表單的啟動事件: System.Windows.Forms.Control.HandleCreated System.Windows.Forms
linux下VI編輯器命令大全(超級完整版)
NOTICE:把這裡提到的命令牢記心間,行走LINUX才能輕鬆自如! 這是基本功,練就此身本領後,方可學習上乘功夫…… 如若不按此步驟修練,結果會經脈盡斷,真氣逆行,哈哈哈! XP 交換兩個字元位置 ddp 上下兩行調換 J 上下兩行合併 dG 刪除所有行 d$ 從當前位置刪除到行尾 y$ 從當前位置複製到行
OpenCV人臉識別的原理 (原文完整版)
http://www.educity.cn/wenda/358439.html “人臉識別”是一個在計算機視覺和生物特徵識別領域十分活躍的話題。這個主題已經被給力地研究了25年,並且最終在安全、機器人學、人機互動、數碼攝像機、遊戲和娛樂領域得到了廣泛應用。 “人臉
對 HashMap remove 有一些元素無法清除的現象 總結(不完整版)
今天寫專案的時候發現了這樣的一個奇怪的現象: 下面將我寫的原始碼貼出來 searchedData 是我定義好的一個 並且資料put成功的一個HashMap,並且MapKey也保證了一致,也保證不會出現OutOfIndexException for (int i =
快速冪運算(入門完整版)
快速冪取模演算法 所謂的快速冪,實際上是快速冪取模的縮寫,簡單的說,就是快速的求一個冪式的模(餘)。在程式設計過程中,經常要去求一些大數對於某個數的餘數,為了得到更快、計算範圍更大的演算法,產生了快速冪取模演算法。 我們先從簡單的例子入手:求x^n % mod 。 演算法1.首先直接地來設計這個演算法: in
快速冪||取余運算 (分治算法)
strong 分享 .cn img 思路 while 指數 快速冪 ron #include<iostream>using namespace std;long b,p,k;long skt=1;int we,tsm;int ksm(long b,long p
漫畫:什麼是快速排序?(完整版)
同氣泡排序一樣,快速排序也屬於交換排序,通過元素之間的比較和交換位置來達到排序的目的。 不同的是,氣泡排序在每一輪只把一個元素冒泡到數列的一端,而快速排序在每一輪挑選一個基準元素,並讓其他比它大的元素移動到數列一邊,比
markdown 入門教程(完整版)
Markdown是一種可以使用普通文字編輯器編寫的標記語言,通過簡單的標記語法,它可以使普通文字內容具有一定的格式。 1. 標題 Markdown支援6種級別的標題,對應html標籤 h1 ~ h6 # h1 ## h2 ### h3 #### h4 ##### h5 ###### h6
快速排序及快速排序的優化(完整版)
快速排序的的基本思想: 設陣列a中存放了n個數據元素,low為陣列的低端下標,high為陣列的高階下標,從陣列a中任取一個 元素(通常選取a[ow])作為標準,調整陣列a中各個元素的位置,使排在標準元素前面的元素的關鍵字均小於標準元素的關鍵字,排在標準元素後面元素的
C語言實現快速排序(完整版)DVE-C++編譯通過
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLINES 5000 //進行排序的最大文字行 char *lineptr[MAXLINES]; //指向文字行的指標陣列 i
快速冪+分治(洛谷P1045 麥森數 noip2003)
高精 進制 素數 str c++ efi ref == com 形如的素數稱為麥森數,這時一定也是個素數。但反過來不一定,即如果是個素數,不一定也是素數。到1998年底,人們已找到了37個麥森數。最大的一個是,它有909526位。麥森數有許多重要應用,它與完全數密切相關