1. 程式人生 > >快速冪運算(入門完整版)

快速冪運算(入門完整版)

結合律 ((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位。麥森數有許多重要應用,它與完全數密切相關