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

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

快速冪取模演算法

所謂的快速冪,實際上是快速冪取模的縮寫,簡單的說,就是快速的求一個冪式的模(餘)。在程式設計過程中,經常要去求一些大數對於某個數的餘數,為了得到更快、計算範圍更大的演算法,產生了快速冪取模演算法。

我們先從簡單的例子入手:求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;
}

相關推薦

快速運算(入門整版)

快速冪取模演算法 所謂的快速冪,實際上是快速冪取模的縮寫,簡單的說,就是快速的求一個冪式的模(餘)。在程式設計過程中,經常要去求一些大數對於某個數的餘數,為了得到更快、計算範圍更大的演算法,產生了快速冪取模演算法。 我們先從簡單的例子入手:求x^n % mod 。 演算法1.首先直接地來設計這個演算法: in

快速運算入門整版

結合律 ((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

基礎快速運算

std -a main 基礎 快速求冪 原創 之前 暫時 names 淺析快速冪 首先,舉個例子(假設數據全為long long型)。 例題:輸入a,n, 求a的n次方(a > 0)。 看到這個例題,肯定是思路滾滾來啊,不就是相當於n個a相乘嗎?於是乎,就上代碼

漫畫:什麼是快速排序?(整版

同氣泡排序一樣,快速排序也屬於交換排序,通過元素之間的比較和交換位置來達到排序的目的。 不同的是,氣泡排序在每一輪只把一個元素冒泡到數列的一端,而快速排序在每一輪挑選一個基準元素,並讓其他比它大的元素移動到數列一邊,比

埃式篩法+快速運算

1.埃式篩法 應用:對很多整數進行素性測試-->要列舉n以內的素數 思路:2--n範圍內的所有整數,依次遍歷。遍歷過程中如果該數是素數則將其的倍數都劃去(可以想象他的倍數一定為非素數)。遍歷完成後。就可以列舉n以內的素數了。 模板: void sieve(int

【資源】100頁機器學習入門整版,初學者必備!

【導讀】近日,作者Andriy Burkov放出了他撰寫的《The Hundred-Page Machine Learning Book》的這本書的最新版,只有100頁,目標是任何只要有基礎數學知識的人都能看懂的機器學習書籍。這本書的十一個章節最新版都已經在網站上公開,本書將涵蓋監督學習和非監督學習

JavaWeb:資料庫與MyBatis入門整版

 步驟1: 初識資料庫操作 本步驟主要介紹MySQL資料庫的基本操作,以及如何使用JDBC操作資料庫,還有單元測試工具JUnit的使用,最後是一個JDBC的綜合案例——留言板。第1課MySQL基礎之資料型別與表的管理MySQL資料庫的安裝、資料型別、表的管理等內容。第2課

【演算法】快速運算

在計算 xn 時,我們會怎麼算呢?如果只是x * x * x * ... * x 這樣每個數乘起來計算 n 次的的話,雖然演算法簡單,但是複雜度為 O(n) ,往往不能滿足要求。讓我們來考慮加速冪運算的方法。 如果 n = 2k ,可以將其表示為&

黑客入門整版教程

看完的人10個有9個成了黑客 看完的人10個有9個成了黑客 還有一個是BC 然而看完的人 視力全下降1度 黑客的基本技能 1、黑客的精神態度是很重要的,但技術則更是重要。黑客的態度雖然是無可取代,隨著新科技的發明和舊技術的取代,這些工具隨時間在慢

(擴充套件)歐幾里得演算法、素性測試、埃式篩法、區間篩法、快速運算

來自挑戰程式設計競賽2.6 數學問題的解題竅門 1.歐幾里得演算法 求解最大公約數,時間複雜度在O(log max(a,b))以內,可以看出,輾轉相除法是非常高效的 int gcd(int a,int b) { return (b==0)?a:gcd(b,a%b);

100頁機器學習入門整版,初學者必備!

導讀:近日,Gartner機器學習團隊負責人Andriy Burkov放出了他撰寫的《The Hundred-Page Machine Learning Book》的這本書的最新版,只有100頁,目標是任何只要有基礎數學知識的人都能看懂的機器學習書籍。   這本書的十一個章節最新版

基本快速運算

#include<cstdio>#include<cstdlib>#include<iostream>using namespace std;int pow(int a,int b){if(b==1)return a;else{int c=

快速運算的簡單程式碼

快速冪求a的b次方 int pow(int a,int b) { int ans=1,base=a; while(b!=0) { if(b&1!=0)    

快速運算應用

先來一個什麼是快速冪運算的講解部落格網址點選開啟連結,別人寫的然後理解了什麼是快速冪運算後這裡要寫的就是它的一個應用,包含了埃氏篩法算區間素數的方法題目:Carmichael Numbers (UVa No.10006)大致意思是:我們把對任意的1<x<n都有xn

快速運算詳解

 快速冪運算對於一個求很大冪運算的模來講,對於取模來說  (a*b)%c=(a%c)*(b%c)%c直接用下列# include<stdio.h> # include<time.h> int main(){ int a=2,sum=1; doubl

快速運算

#include <iostream> #include <cstdio> using namespace std; typedef long long int LL; LL fast_pow(LL x,LL n,LL m) { LL r

qt creator快速入門.pdf 高清整版

內容簡介 《Qt Creator快速入門》作為全面介紹Qt、QtCreator和QtQuick的入門級教材,也是市面上第一套詳細介紹QtCreator和QtQuick的教材。書中的內容包含了Qt基礎、圖形動畫、多媒體、資料庫、網路通訊、WebKit以及QtQ

洛谷 P1226 取余運算||快速 題解

代碼 amp base iostream div 其中 tro std strong 此文為博主原創題解,轉載時請通知博主,並把原文鏈接放在正文醒目位置。 題目鏈接:https://www.luogu.org/problem/show?pid=1226 題目描述

Luogu P1226 取余運算||快速(數論,分治)

span 水題 spa 數論 urn 等於 註意 nbsp int P1226 取余運算||快速冪 題目描述 輸入b,p,k的值,求b^p mod k的值。其中b,p,k*k為長整型數。 輸入輸出格式 輸入格式: 三個整數b,p,k. 輸出格式: 輸出“b^p

快速||取余運算 (分治算法)

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