快速幂:
方法一::
首先快速幂有几个公式:
1.(a^b)mod c=( a mod c)^b mod c;
(ab) mod c=[(a mod c)*( b mod c)] mod c; (积的取余等于取余的积取余)
快速幂算法依赖于一下两个公式:
a^b mod c=((a²)^(b/2)) mod c , b是偶数
a^b mod c=((a²)(b/2)*a) mod c ,b是奇数
有了上述两个公式,我们可以得出一下结论:
1.如果b是偶数,我们可以记k=a²modc,那么(k)^(b/2)mod c 就可以了.
2.如果b是奇数,我们也可以记k=a²modc,那么((k)^(b/2)mod c就可以了
所以有了最终的算法:快速幂算法(log b):
int ans=1;
a=a%c;
while(b>0)
{
if(b%2==1) ans=(ans*a)%c;
b=b/2;
a=(a*a)%c;
}
将上述代码结构化,也就是写成函数:
int PowerMod(int a,int b,int c)
{
int ans=1;
a=a%c;
while(b>0)
{
if(b%2==1) ans=(ans*a)%c;
b=b/2;
a=(a*a)%c;
}
return ans;
}
方法二::
用位运算来实现:
1.b&1(取b的二进制最低位(即第0位) 判断b是否为奇数,是则为1
)
2.b>>1(去掉b的二进制最低位(即第0位)
)
所以代码实现为:
#include<iostream>
#include<cstdio>
using namespace std;
int pow3(int x,int n)
{
if(n==0) return 1;
else
{
while((n&1)==0)
{
n>>=1;
x*=x;
}
}
cout<<n<<endl;
int result=x;
n>>=1;
while(n!=0)
{
x*=x;
cout<<x<<endl;
if((n&1)!=0)
result*=x;
n>>=1;
}
return result;
}
int main()
{
int x,n;
cin>>x>>n;
cout<<pow3(x,n)<<endl;
}
矩阵快速幂:
矩阵快速幂其实就是矩阵相乘然后套用快速幂.这个首先来写一下矩阵相乘
const int N=100;
int c[N][N];
void multi(int a[][N],int b[][N],int n)
{
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c[i][j]+=a[i][k]*b[k][j];
}
然后了解一下矩阵相乘原理: 两个相乘是要一行和一列对应乘,那么矩阵乘法是需要A的行数与B的列数相等的, 矩阵快速幂只会用到方阵(n*n)
矩阵快速幂是用来求解递推式的,所以第一步先要列出递推式:
f(n)=f(n-1)+f(n-2)
第二步是建立矩阵递推式,找到转移矩阵:
,简写成T * A(n-1)=A(n),T矩阵就是那个2*2的常数矩阵,而
这里就是个矩阵乘法等式左边:1*f(n-1)+1*f(n-2)=f(n);1*f(n-1)+0*f(n-2)=f(n-1);
所以这里相乘就是矩阵n-1次相乘,然后输出第一行第二个元素,也就是a[0][1]这里可以练习一下poj 3070,其实就是矩阵快速幂的模板题
然后给一些简单的递推式:
1.f(n)=a*f(n-1)+b*f(n-2)+c;(a,b,c是常数)
2.f(n)=c^n-f(n-1) ;(c是常数)
快速乘:
问题:
求 (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;
这样代码如下:
long long multi(long long a,long long b,long long m) {
long long ans=0;
while(b) {
if(b&1) (ans+=a) %= m;
(a=a*2) %= m;
b/=2;
}
return ans;
}