快速幂取模及其应用

快速幂取模


用法:用于求解 a 的 b 次方,而b是一个非常大的数,用O(n)的复杂度会超时。那么就需要这个算法,注意它不但可以对数求次幂,而且可用于矩阵快速幂。


假如求 x ^ n 次方


我们可以把 n 表示为 2^k1 + 2^k2  + 2^k3....,可以证明所有数都可以用前式来表示。(其实就是二进制表示数的原理,k1,k2……就是二进制的每一位)


那么 x^n = x^2^k1 * x^2^k2 * x^2^k3......


那么就可以利用二进制来加快计算速度了。


假如 x^22 , 22转化为二进制为 10110, 即 x^22 = x^16 * x^4 * x^2;


那么是不是可以在O(logn)的复杂度求解。


代码:


[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. typedef long long LL;  
  2. LL fun(LL x,LL n,)  
  3. {  
  4.     LL res=1;  
  5.     while(n>0)  
  6.     {  
  7.         if(n & 1)  
  8.             res=(res*x)%Max;  
  9.         x=(x*x)%Max;  
  10.         n >>= 1;  
  11.     }  
  12.     return res;  
  13. }  


那么假如让你求一个矩阵的很大的次方幂呢,当然我们同样可以求解。


比如我们都知道斐波那契数列可以用矩阵来求



当求第非常大的一个斐波那契数的后几位时我们可以用上面方法求解了。


方法和上面的方法一模一样,只是把数 x 变成了一个矩阵。


注意代码中矩阵的存法,很好用,题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=148


[cpp]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. #include <cstdio>  
  2. #include <iostream>  
  3. #include <vector>  
  4.   
  5. using namespace std;  
  6. typedef vector<int> vec;  
  7. typedef vector<vec> mat;  
  8. typedef long long LL;  
  9. const int N = 10000;  
  10. mat mul(mat a,mat b)  //矩阵乘法  
  11. {  
  12.     mat c(a.size(),vec(b[0].size()));  
  13.     for(int i=0;i<a.size();i++)  
  14.     {  
  15.         for(int k=0;k<b.size();k++)  
  16.         {  
  17.             for(int j=0;j<b[0].size();j++)  
  18.                 c[i][j] = ( c[i][j] + a[i][k] * b[k][j] ) % N;  
  19.         }  
  20.     }  
  21.     return c;  
  22. }  
  23.   
  24. mat solve_pow(mat a,int n) //快速幂  
  25. {  
  26.     mat b(a.size(),vec(a.size()));  
  27.     for(int i=0;i<a.size();i++)  
  28.         b[i][i]=1;  
  29.     while(n>0)  
  30.     {  
  31.         if(n & 1)  
  32.             b=mul(b,a);  
  33.         a=mul(a,a);  
  34.         n >>= 1;  
  35.     }  
  36.   
  37.     return b;  
  38. }  
  39. LL n;  
  40. void solve()  
  41. {  
  42.     mat a(2,vec(2));  
  43.     while(~scanf("%d",&n) && n!=-1)  
  44.     {  
  45.         a[0][0]=1,a[0][1]=1;  
  46.         a[1][0]=1,a[1][1]=0;  
  47.         a=solve_pow(a,n);  
  48.         printf("%d\n",a[1][0]);  
  49.     }  
  50. }  
  51. int main()  
  52. {  
  53.     solve();  
  54.     return 0;  
  55. }  

原文:http://blog.csdn.net/y990041769/article/details/22311889


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值