快速求幂

例题:nyoj 102 快速求幂

1 //a^b mod c=(a mod c)^b mod c//很容易设计出一个基于二分的递归算法。

 2 #include<stdio.h>

 3 #include<stdlib.h>

4 //快速幂算法,数论二分

 5 long long powermod(int a,int b, int c) //不用longlong就报错,题目中那个取值范围不就在2的31次方内

6 {

 7     long long t;

8     if(b==0)  return 1%c;

9     if(b==1)  return a%c;

10     t=powermod(a,b/2,c);//递归调用,采用二分递归算法,,注意这里n/2会带来奇偶性问题

11     t=t*t%c;//二分,乘上另一半再求模

12     if(b&1)  t=t*a%c;//n是奇数,因为n/2还少乘了一次a

13     return t;

14 }

15 int main()

16 {

17     int n;

18     long long a,b,c;

19     scanf("%d",&n);

20     while(n--)

21     {

22         scanf("%lld%lld%lld",&a,&b,&c);

23         printf("%lld\n",powermod(a,b,c));

24     }

25       return 0;

 26}        

刚开始用pow函数求次幂,后来发现结果以及参数都为浮点型,我就强行转化为(int)得出的结果不对,看来这种方法不行

一旦遇到高次方连乘,一定要记得快速幂。

2:快速幂取模

快速幂取模就是在O(logn)内求出a^n mod b的值。算法的原理是ab mod c=(a mod c)(b mod c)mod c

因此很容易设计出一个基于二分的递归算法。

心得:long long 2^63 大概是 9*10^18,假如999999999*999999999*999999999肯定超过int 64位的长度了,所以一定溢出。
以下是我的代码,以下代码必须保证输入的是合法的表达式,比如不能出现0^0 mod b:

long exp_mod(long a,long n,long b)
{
long t;
if(n==0) return 1%b;
if(n==1) return a%b;
t=exp_mod(a,n/2,b);
t=t*t%b;
if((n&1)==1) t=t*a%b;
return t;
}
3:高次方求模:

比如a的b次方对c求模
我们可以把b 化为二进制形式看那一位有1
比如b=10101则  a^b=a^(10000)*a^(100)*a^(1)
以函数形式体现:
long long a,b,c;
void han()
{
    long long t,s;
    for(t=a,s=1;b;b>>=1,t*=t,t%=c)//用b>>=1查看b中1
     if(b&1){s*=t;s%=c;}
    printf("%lld\n",s%c); 
}

    4:据说,矩阵快速幂在递推式优化上相当神奇,而且效率很高。。。

  两矩阵相乘,朴素算法的复杂度是O(N^3)。如果求一次矩阵的M次幂,按朴素的写法就是O(N^3*M)。既然是求幂,不免想到快速幂取模的算法,这里有快速幂取模的介绍,a^b %m 的复杂度可以降到O(logb)。如果矩阵相乘是不是也可以实现O(N^3 * logM)的时间复杂度呢?答案是肯定的。

5:同余幂的思想

求出同余幂bn mod m,其中b,n,m都是比较大的整数。例如取b=12345678,n=456789,直接计算显然是不可行的,可以把n按二进制展开,则n=456789就变成了1101111100001010101,这样每次只需要求b mod m,b2 mod m,... b2^(k-1) mod m,然后把对应位置上的二进制是1的项乘起来,每次乘完后求除m的余数即可,大大降低了计算的复杂度。

这里还要用一些同余定理

(a+b)mod m=((a mod m)+(b mod m))mod m;

a*b mod m=(a mod m)*(b mod m) mod m;

a^b mod m=(a mod m)^b mod m;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值