数论--快速幂,矩阵快速幂

1.快速幂:

当求a的b次方的时候,我们可以写一个函数一次循环求出,又可以用math文件里面的pow(double a,double b)解决

但是,当b非常大还要取模呢?O(n)的时间复杂度也不行怎么办?

可以用快速幂的方法:

要求a^b时,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),例如当b==11时

             a^11=a^(2^0+2^1+2^3)=a^(2^0)*a^(2^1)*a^(2^3)

实现时要用到位运算:

b&1是取b二进制的末尾

b>>1是去掉b二进制的末尾

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4  
 5 #define ll long long 
 6  
 7 ll pow_mod(ll a,ll b,ll p)  //(a^b)%p 
 8 {
 9      ll ans=1;
10      while(b)
11      {
12          if(b&1)
13          {
14              ans=(ans*a)%p;
15          }
16          a=(a*a)%p;
17          b>>=1;
18      }
19      return ans;
20  }
21  
22  
23  int main()
24  {
25      ll a,b,p;
26      cin>>a>>b>>p;
27      cout<<pow_mod(a,b,p)<<endl;  
28  }

其中,a=(a*a)%p理解起来就是:第0次a=a^(2^0);//初始值 ,第一次a=a*a相当于a^(2^1),第二次相当于a^(2^2).......a^(2^n),再结合上面a^11=a^1011(二进制)=a^(2^0)*a^(2^1)*a^(2^3),

对应的就是,在第0次,第1次,第3次的时候,ans=(ans*a)%p;

而在第0次,第1次,第3次的时候ans要更新,是因为11的二进制1011的第0位,第1位,第3位是1(即if(b&1),当前b的末尾是1)

讲解over,例题POJ 1995

2.矩阵快速幂:

原理与快速幂一样,不过就是把整数换成了矩阵,把整数的乘法换成了矩阵的乘法

先贴出代码:

 1 # include<cstdio>
 2 # include<cstring>
 3 using namespace std;
 4 
 5 #define NUM 50
 6 int MAXN,n,mod;
 7 
 8 struct Matrix//矩阵的类
 9 {
10     int a[NUM][NUM];
11     void init()           //将其初始化为单位矩阵
12     {
13         memset(a,0,sizeof(a));
14         for(int i=0;i<MAXN;i++)
15             a[i][i]=1;
16     }
17 } A;
18 
19 Matrix mul(Matrix a,Matrix b)  //(a*b)%mod  矩阵乘法
20 {
21     Matrix ans;
22     for(int i=0;i<MAXN;i++)
23         for(int j=0;j<MAXN;j++)
24         {
25             ans.a[i][j]=0;
26             for(int k=0;k<MAXN;k++)
27                 ans.a[i][j]+=a.a[i][k]*b.a[k][j];
28             ans.a[i][j]%=mod;
29         }
30     return ans;
31 }
32 
33 Matrix pow(Matrix a,int n)    //(a^n)%mod  //矩阵快速幂
34 {
35     Matrix ans;
36     ans.init();
37     while(n)
38     {
39         if(n%2)//n&1
40             ans=mul(ans,a);
41         n/=2;
42         a=mul(a,a);
43     }
44     return ans;
45 }
46 
47 void output(Matrix a)//输出矩阵
48 {
49     for(int i=0;i<MAXN;i++)
50         for(int j=0;j<MAXN;j++)
51             printf("%d%c",a.a[i][j],j==MAXN-1?'
':' ');
52 }
53 int main()
54 {
55     Matrix ans;
56     scanf("%d%d%d",&MAXN,&n,&mod);
57     for(int i=0;i<MAXN;i++)
58         for(int j=0;j<MAXN;j++)
59         {
60             scanf("%d",&A.a[i][j]);
61             A.a[i][j]%=mod;
62         }
63     ans=pow(A,n);
64     output(ans);
65     return 0;
66 }

请看到,mul() 函数,这个是矩阵的乘法

再看到第33行pow()函数,这个就是矩阵快速幂,跟上面的快速幂比较,是不是很像?

只不过用mul() 函数代替了  a=(a*a)%p的运算罢了

讲解over

原文地址:https://www.cnblogs.com/eastblue/p/7624370.html