算法錄 之 快速冪快速乘和矩陣快速冪。


1:

  問題如下:

  求 a^n % m 的值是多少?n是1到10^18次方的一個整數。

 

  求一個數的n次方,朴素的算法就是直接for循環,O(N)的復雜度。

  但是對於這個問題n實在是太大了,O(N)也會超時,那么需要更快的算法,快速冪算法。

 

  要求 a^n,如果知道了 a^(n/2) 次方的話,再來個平方就可以了。

  那么按照這個思路就能運用分治的思想了。

  代碼如下:  

1 int _pow(int a,long long n,int m) {
2     if(n==0) return 1 % m;
3 
4     long long t=_pow(a,n/2,m);
5 
6     if(n%2==1) return (t*t*a) % m;
7     else return (t*t) % m;
8 }

  如上運用分治的思想,只需要logN的復雜度就可以得到答案。

 

2:

  問題如下:

  f(1)=1, f(2)=1 , f(n)=a*f(n-1)+b*f(n-2),輸出n和m,求 f(n) % m 的值。n是1到10^18次方的數。

 

  朴素的想法同上,直接一個for循環遞推過去,這樣復雜度是O(N)的,還是比較慢。

  然后想到高中的數學問題,用特征方程求這個遞推式的非遞推通項方程,求出是 f(n)=c1*x1^n+c2*x2^n ,這樣的話應用前面的快速冪就可以求解了。

  但是x1和x2大部分情況是小數,這是求出來會有誤差而且沒法取模,並不能算出精確值來。

 

  考慮矩陣這種數學工具,構造矩陣:

  

  則求 f(n) 的話如下:

  

  那么只要用快速冪求出矩陣的n-2次方來,因為都是整數,所以不會有精度問題,也就得到了正確答案。

  也就是矩陣快速冪。

 

3,快速乘:

  問題:

  求 (a*b) % m 的值,其中 a,b,m 是1到10^18。

  如果直接乘的話,因為a和b還有m都很大,那么會溢出long long,所以需要一些方法。

  朴素的想法是用數組模擬高精度,但是比較麻煩。

 

  還有更好的方法:

  求乘法的列豎式,

  1234*213=1234*3+1234*10*1+1234*10^2*2;

  那么如果變成二進制的話 10101 × 1011 = 10101*1+10101*2^1*1+10101*2^2*0+10101*2^3*1;

  這樣代碼如下:

 1 long long multi(long long a,long long b,long long m) {
 2     long long ans=0;
 3 
 4     while(b) {
 5         if(b&1) (ans+=a) %= m;
 6         (a=a*2) %= m;
 7         b/=2;
 8     }
 9 
10     return ans;
11 }

  就是模擬了二進制的豎式乘法,因為每次最多×2,所以不會溢出。

  這樣的復雜度是 logN 的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM