快递幂算法
‘壹’ 快速幂算法原理
快速幂
顾名思义,快速幂就是快速算底数的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;
}
‘贰’ 用递归 快速幂怎么写
是求(a的b次幂)mod c的值吧?
#include<stdio.h>
int res(int a, int b, int c);
void main()
{int a,b,c;
scanf("%d %d %d",&a,&b,&c);
printf("%d\n",res(a,b,c));
}
int res(int a, int b, int c) {
if (b == 1) return a % c;
if (b % 2) return a * res (a, b / 2, c) * res (a, b / 2, c) % c;
else return res (a, b / 2, c) * res (a, b / 2, c) % c;
}
‘叁’ 快递体积的重量计算公式是怎么样的
快递体积的重量计算公式,以顺丰为例,列举如下:
1、【顺丰即日/次晨/标快】
同城、省内件以及经济区域内互寄,体积重量=长(CM)×宽(CM)×高(CM)÷12000;
省外跨经济区域互寄,体积重量=长(CM)×宽(CM)×高(CM)÷6000;
(经济区域包含:京津冀区域,江浙沪皖区域,,川渝区域,黑吉辽区域)
2、【顺丰特惠】 体积重量=长(CM)×宽(CM)×高(CM)÷12000;
3、【重货包裹/小票零担/冷运到家】 体积重量=长(CM)×宽(CM)×高(CM)÷6000;
4、【冷运零担】 体积重量=长(CM)×宽(CM)×高(CM)÷3000;
5、【港澳台(服务)】体积重量=长(CM)×宽(CM)×高(CM)÷6000
6、【国际快递(服务)】体积重量=长(CM)×宽(CM)×高(CM) ÷5000
100KG以下,续重以0.5KG为计重单位,不足0.5kg,按0.5kg计;100KG及以上,四舍五入取整数。
‘肆’ 快递怎么算运费
快递的运费计算公式:(总重量-首重重量)*续重价格+首重价格=快件的运费
较多情况下按重量计费,以毛重为总的重量,以KG为计量单位。不同的省份会收取不同的运费价格,会有首重价格和续重价格。比较少的情况会按体积重计价,快递会对长、宽、高进行单边限制,超出则会按长*宽*高/6000,算出来的体积重,然后再按照上面的公式进行计价算运费。
在实际工作过程中,对于快递批量进行计价的,还可以通过运费计算插件,连接电子称,进行自动计算。提高工作效率。运费计算插件一般需要将运费价格表的明细录入,才能进行自动计算,所以一定要理解运费的计算。
国际快递收费标准
国际快递包裹重量分实际重量和体积重量两种,快递公司将以两种重量中大的一项为计费依据运输物品到国外,主要包括两大类的费用,运费和当地国的税费。
国际快递包裹的货物不足0.5公斤的,按0.5公斤计费,要了解目的地国家都要收哪些费用,因为各个国家都不一样,所以要注意国际快递出口价格资费变化较大,需发快递邮包时,应先联系客服人员确认价格。
‘伍’ 快递费用算法
首重就是不超过1公斤,续重是1公斤以上
比如首重10元/公斤,续重5元/公斤 有6公斤,那就是6公斤×5元+5元
加的5元是首重的10元-续重的5元
也可以用10元+5公斤×5元
希望对你有所帮助~~
‘陆’ 不理解矩阵快速幂如何用于求斐波那契数列第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;
}
还有一点,就是你的矩阵相乘后两项写错了,自己对比一下改过来吧。
这样就能得到你想要的结果了。
‘柒’ 快速幂是什么
解释一下a^b mod c:
a^b mod c=a^(f[0]*2^0+f[1]*2^1+f[2]*2^2...f[t]*2^t)
因为 a*b mod c= ((a mod c) *b) mod c
所以
a^b mod c=(((f[0]*2^0 mod c)*f[1]*2^1 mod c)......*f[t]*2^t mod c)
用这种方法解决a^b mod c 时间复杂度
2^t<=b<2^(t+1)
t<=log(2)b<t+1
因为 b是个整数 所以
t=log(2)b
时间复杂度比直接循环求a^b大大的降低了
模取幂运算
事实上,m^e mod n可以直接计算,没有必要先算m^e。
m^e mod n叫做模取幂运算,根据简单的数论知识,很容易设计一个分治算法。具体如下:
设<b[k], b[k-1],...,b[1],b[0]>是整数b的二进制表示(即b的二进制有k+1位,b[k]是最
高位),下列过程随着c的值从0到b成倍增加,最终计算出a^c mod n
Molar-Exponentiation(a, b, n)
1. c ← 0
2. d ← 1
3. 设<b[k],b[k-1],..b[0]>是b的二进制表示
4. for i←k downto 0
5. do c ← 2c
6. d ← (d*d) mod n
7. if b[i] = 1
8. then c ← c + 1
9. d ← (d*a) mod n
10. return d
首先说明一下,上述伪代码中用缩紧表示语句之间的层次关系,例如第5~9行都是for循环体
内的语句,第8~9行都是then里面的语句。这是我比较喜欢的一种表示方法 ;)
上述伪代码依次计算出的每个幂或者是前一个幂的两倍,或者比前一个幂大1。过程依次从
右到左逐个读入b的二进制表示已控制执行哪一种操作。循环中的每次迭代都用到了下面的
两个恒等式中的一个:
a^(2c) mod n = (a^c mod n)^2
a^(2c+1) mod n = a * (a^c mod n)^2
用哪一个恒等式取决于b[i]=0还是1。由于平方在每次迭代中起着关键作用,所以这种方法
叫做“反复平方法(repeated squaring)”。在读入b[i]位并进行相应处理后,c的值与b的
二进制表示<b[k],b[k-1],..b[0]>的前缀的值相同。事实上,算法中并不真正需要变量c,
只是为了说明算法才设置了变量c:当c成倍增加时,算法保持条件d = a^c mod n 不变,直
至c=b。
如果输入a,b,n是k位的数,则算法总共需要执行的算术运算次数为O(k),总共需要执行的位
操作次数为O(k^3)。
‘捌’ 如何计算快速幂,比如 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;
}
‘玖’ 次方的快速算法
次方有两种快速算法:
第一种是直接用乘法计算,例: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次方。
(9)快递幂算法扩展阅读:
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。