ACM数论——快速幂


快速幂定义:

  顾名思义,快速幂就是快速算底数的n次幂。其时间复杂度为 O(log₂N), 与朴素的O(N)相比效率有了极大的提高。

原理:

  以下以求a的b次方来介绍:

    把b转换成二进制数。该二进制数第i位的权为   
    例如
        
    11的二进制是1011    
    11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1
    因此,我们将a¹¹转化为算   

快速幂位运算:

1 LL pow_mod(LL a, LL b, LL p){//a的b次方取余p 
2     LL ret = 1;
3     while(b){
4         if(b & 1) ret = (ret * a) % p;
5         a = (a * a) % p;
6         b >>= 1;
7     }
8     return ret;
9 }
View Code

快速乘:

  为了防止求a*b \mod{m}的时候溢出,通常会使用一种叫做“快速乘”的算法。

LL mul(LL a, LL b, LL p){//快速乘,计算a*b%p 
    LL ret = 0;
    while(b){
        if(b & 1) ret = (ret + a) % p;
        a = (a + a) % p;
        b >>= 1;
    }
    return ret;
}
View Code

 

  具体拿一个题目来示例,题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5187

  这个题先找规律,然后在求快速乘法和快速幂结合起来。题目推出来通式是:2n-2

 

#include<iostream>
#include <cstdio>
using namespace std;
typedef long long LL;

LL fast_multi(LL m, LL n, LL mod)//快速乘法 
{
    LL ans = 0;//注意初始化是0,不是1 
    while (n)
    {
        if (n & 1)
            ans += m;
        m = (m + m) % mod;//和快速幂一样,只不过这里是加 
        m %= mod;//取模,不要超出范围 
        ans %= mod;
        n >>= 1;
    }
    return ans;
}
LL fast_pow(LL a, LL n, LL mod)//快速幂 
{
    LL ans = 1;
    while (n)
    {
        if (n & 1)
            ans = fast_multi(ans, a, mod);//不能直接乘 
        a = fast_multi(a, a, mod);
        ans %= mod;
        a %= mod;
        n >>= 1;
    }
    return ans;
}

int main()
{
    LL n, p;
    while (~scanf("%I64d %I64d", &n, &p))
    {
        if (n == 1)//特判一下 
        {
            printf("%I64d\n", 1 % p);
            continue;
        }
        printf("%I64d\n", (fast_pow(2, n, p) - 2 + p) % p);//这一步注意,不要为负数 
    }
    return 0;
}
View Code

 


 

posted on 2018-05-06 16:05  slp0622  阅读(466)  评论(0编辑  收藏  举报