快速幂算法
㈠ 不理解矩阵快速幂如何用于求斐波那契数列第n项%m的余数,望大神讲解,越详细越好
按照正常的逻辑是只要求a[2][2]={1,1,1,0}这个矩阵的n次方就可以得到斐波那契数列的第n项(即a[0][1])的值。但是你忽略了一点,就是你在求a[0][1],a[1][0],a[1][1]的值的时候你的a[0][0]的值其实已经改变了,导致你求得的a[0][1]的值不正确,继而影响到a[1][0]和a[1][1]的值。
因此,我们在遍历这四个值的时候是不能改变其中任何一个的,只有改完之后才能去改变它的值。所以我们可以用几个变量先将求得的新矩阵各值存起来,如下:
#include<stdio.h>
inta[2][2]={1,1,1,0},b[2][2]={1,1,1,0};//使用两个二维数组表示快速幂算法要用到的矩阵
intmain()
{
intn,m,i,j,t,u;
inta1,a2,a3,a4;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(m==-1&&n==-1)//当输入的m.n值为-1时结束整个算法
return0;
/*以下是对于第n项斐波那契数的计算*/
if(n==0)
a[0][0]=0;
elseif(n==1||n==2)
a[0][0]=1;
else
{
for(i=3;i<=n;i++)
{
a1=a[0][0]*b[0][0]+a[0][1]*b[1][0];
a2=a[0][0]*b[0][1]+a[0][1]*b[1][1];
a3=a[1][0]*b[0][0]+a[1][1]*b[1][0];
a4=a[1][0]*b[0][1]+a[1][1]*b[1][1];
a[0][0]=a1;
a[0][1]=a2;
a[1][0]=a3;
a[1][1]=a4;
}
}
t=a[0][0];
a[0][0]=1;//重置矩阵
a[0][1]=1;
a[1][0]=1;
a[1][1]=0;
if(m==0)
a[0][0]=0;
elseif(m==1||m==2)
a[0][0]=1;
else
{
for(j=3;j<=m;j++)
{
a1=a[0][0]*b[0][0]+a[0][1]*b[1][0];
a2=a[0][0]*b[0][1]+a[0][1]*b[1][1];
a3=a[1][0]*b[0][0]+a[1][1]*b[1][0];
a4=a[1][0]*b[0][1]+a[1][1]*b[1][1];
a[0][0]=a1;
a[0][1]=a2;
a[1][0]=a3;
a[1][1]=a4;
}
}
u=a[0][0];
a[0][0]=1;//重置矩阵
a[0][1]=1;
a[1][0]=1;
a[1][1]=0;
t=t%u;
printf("%d ",t);
}
return0;
}
还有一点,就是你的矩阵相乘后两项写错了,自己对比一下改过来吧。
这样就能得到你想要的结果了。
㈡ 求快速幂算法c语言实现程序
㈢ 次方的快速算法
次方有两种快速算法:
第一种是直接用乘法计算,例:3⁴=3×3×3×3=81。
第二种则是用次方阶级下的数相乘,例:3⁴=9×9=81
次方最基本的定义是:设a为某数,n为正整数,a的n次方表示为aⁿ,表示n个a连乘所得之结果,如2⁴=2×2×2×2=16。次方的定义还可以扩展到0次方和负数次方等等。
负数次方
由5的0次方继续除以5就可以得出5的负数次方。
例如: 5的0次方是1 (任何非零数的0次方都等于1。)
5的-1次方是0.2 1÷ 5 =0.2
5的-2次方是0.04 0.2÷5 =0.04
因为5的-1次方是0.2 ,所以5的-2次方也可以表示为0.2×0.2=0.04
5的-3次方则是0.2×0.2×0.2=0.008
由此可见,一个非零数的-n次方=这个数的倒数的n次方。
(3)快速幂算法扩展阅读:
0的次方
0的任何正数次方都是0,例:0⁵=0×0×0×0×0=0
0的0次方无意义。
一个数的0次方
任何非零数的0次方都等于1。原因如下:
通常代表3次方
5的3次方是125,即5×5×5=125
5的2次方是25,即5×5=25
5的1次方是5,即5×1=5
由此可见,n≧0时,将5的(n+1)次方变为5的n次方需除以一个5,所以可定义5的0次方为:
5 ÷ 5 = 1。
㈣ 快速幂算法原理
快速幂
顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log2N), 与朴素的O(N)相比效率有了极大的提高。
中文名
快速幂
外文名
Fast Power
时间复杂度
log(n)
性质
快速算底数的n次幂
快速
导航
实现
代码比较
原理
快速幂算法的核心思想就是每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。
让我们先来看一个简单的例子:
3^10=3*3*3*3*3*3*3*3*3*3
3^10=(3*3)*(3*3)*(3*3)*(3*3)*(3*3)
3^10=(3*3)^5
3^10=9^5
9^5=(9^4)*(9^1)
9^5=(9^4)*(9^1)
9^5=(6561^1)*(9^1)
以下以求a的b次方来介绍[1]
把b转换成二进制数。
该二进制数第i位的权为
例如
11的二进制是1011
因此,我们将a11转化为算
实现
快速幂可以用位运算来实现
b and 1{也就是取b的二进制最低位(即第0位)判断b是否为奇数,是则为1}
b shr 1{就是去掉b的二进制最低位(即第0位)}
C++实现为
b & 1//取b二进制的最低位,判断和1是否相同,相同返回1,否则返回0,可用于判断奇偶
b>>1//把b的二进制右移一位,即去掉其二进制位的最低位
以下为pascal的实现:
var a,b,n:int64;
function f(a,b,n:int64):int64;
var t,y:int64;
begin
t:=1; y:=a;
while b<>0 do begin
if(b and 1)=1 then t:=t*y mod n;
y:=y*y mod n;{这里用了一个技巧,y*y即求出了a^(2^(i-1))不知道这是什么的看原理
a^(2^(i-1))*a^(2^(i-1))=a^(2^i)
而且一般情况下a*b mod c =(a mod c)*(b mod c) mod c}
b:=b shr 1;{去掉已经处理过的一位}
end;
exit(t);
end;
begin
read(a,b,n);{n是模}
writeln(f(a,b,n));
end.
[1]
以下为C的实现,为了方便与pascal的对照,变量全部与上面相同.可以对照查看。
递归版:[2]
ll pow(ll a,ll i){
if (i==0) return 1;
int temp=pow(a,i>>1);
temp=temp*temp%MOD;
if (i&1) temp=(ll)temp*a%MOD;
return temp%MOD;
}
非递归版:
ll f(ll a,ll b,ll n){
int t,y;
t=1; y=a;
while (b!=0){
if (b&1==1) t=t*y%n;
y=y*y%n; b=b>>1;
}
return t;
}
㈤ c语言快速幂代码
int pow( int a, int b )
{
int r = 1, base = a;
while( b != 0 )
{
if( b & 1 )
r *= base;
base *= base;
b >>= 1;
}
return r;
}
㈥ c语言,快速幂代码是什么,怎么用
所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求一个幂式的模(余)。在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快、计算范围更大的算法,产生了快速幂取模算法。
用递归
x^y可如下实现
unsigned long pow(int x, unsigned y)
{
unsigned long tmp;
if(!y) return 1;
tmp = pow(x, y / 2);
if(y % 2 == 0) return (tmp * tmp);
else return (tmp * tmp * x);
}
㈦ 在快速幂运算算法中,为啥把n&1换成n==1就会出错呢
对于 表达式“n&1”表示的是n与1的按位与(其业务逻辑应该是:当且仅当n为奇数时结果为1,其余时候为0,不过我也有段时间不用c++了,可能记错)
对于表达式”n==1“表示的是判断两整数是否相等(其业务逻辑是:当且仅当n为1时结果为true其余时候为false)
这两个业务逻辑不同,结果自然不同
㈧ 如何计算快速幂,比如 x^100000000次方,直接循环很慢。。谢谢了
因为 x^n = (x^(n/2))^2
根据这个公式,可以在 log2N时间内算出乘法幂
递归算法:
int pow(int x,int n)
{
if(n==1) return x;
else if(n&1) //n is odd
{
return x*pow(x,n/2);
}
else
{
return pow(x,n/2);
}
}
非递归算法:
int pow(int x,int n)
{
int temp(x),res(1);
while(n)
{
if(n&1)
{
res *= temp;
}
temp *= temp;
n>>=1;
}
return res;
}