快速幂取模算法

1.快速幂适用问题: 大数据的a^b mod c

2.取模运算的一些公式:

(1)amod c = (a mod c)b mod c

(2)(a*b)mod c = [(a mod c)*(b mod c)]mod c

3.快速幂实现思路

(1)任何数字都可以表示成二进制的01串形式,同理:a^b mod c也可以把b拆成二进制串表示

   b = b0*2^0 + b1 * 2^1 + b2*2^2 + b3* 2^3 + ....bx * 2^x +.....bn* 2^n

所以原式就等于: a^( b0*2^0 + b1 * 2^1 + b2*2^2 + b3* 2^3 + ....bx * 2^x +.....bn* 2^n) mod c;

等价于 : a^b0 * a^(b1*2)  * a^(b2*4)  * a^(b3*8) * ......* a^(bx*2^x) * ....* a^(bn * 2^n);

因为这里的b0....bn不是0就是一,一旦bx=0,则 a^(bx*2^x) =1, 这一项乘与不乘都是一样的,只有这一项的二进制数位置为1才乘进结果。

再进一步发现:如果b0....bn都是一,则 a  a^2 a^4 a^8 a^16...... 每一项不管乘不乘,下一项都是成a = a*a的指数递增变化的。

(2)由上可得 :我们可以枚举b的二进制的每一位,若该位为0,则不乘入结果;若该位为1,则乘入结果;而要乘的是a^x, 不管乘不乘入结果,a都是指数递增的,a = a*a;( a  a^2 a^4 a^8 a^16......)

(3) 如何枚举b的每一位二进制呢? 答案是用b>>=1;来往右移动b的二进制位;用b&1来判断b的最后一个二进制位是否为1,直到b==0结束。

4.实现代码:

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
long long int power(long long a,long long b,long long c)
{
    a=a%c;//先一步取模把a制于c之下
    long long int ans=1;//记录结果
    while(b)
    {
        if(b&1)//如果b的二进制最右边一位为1
            ans=(ans*a)%c;//计入结果
        b>>=1;//b不断右移,枚举二进制位
        a=(a*a)%c;//a不断指数递增(a a^2 a^4 a^8....)
    }
    return ans;
}
int main()
{
    long long int a,b,c;
    while(cin>>a>>b>>c)
    {
        cout<<power(a,b,c)<<endl;
    }
    return 0;
}

5.例题

(1)uva11609 Team

题意:问组合数,规律: n* 2^(n-1)

代码:

#include <iostream>
//#include<bits/stdc++.h>
using namespace std;
long long int power(long long k)
{
    long long int b=k-1;
    long long int a=2;
    long long int ans=1;
    while(b)
    {
        if(b&1)
            ans=(ans*a)%1000000007;
        b>>=1;
        a=(a*a)%1000000007;
    }
    return (ans*k)%1000000007;
}
int main()
{
    int T;
    cin>>T;
    int t=0;
    long long int n;
    while(T--)
    {
        t++;
        cin>>n;
        cout<<"Case #"<<t<<": "<<power(n)<<endl;
    }
    return 0;
}

(2)poj 1995

题意:求 (Ai^Bi +....+ An^Bn)mod M的值

代码:

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

ll power(ll a,ll b,int c)
{
    ll ans = 1;
    a%=c;
    while(b)
    {
        if(b&1)
            ans = (ans*a)%c;
        b>>=1;
        a = (a*a)%c;
    }
    return ans;
}
int main()
{
    int z;
    scanf("%d",&z);
    while(z--){
        int M,H;
        scanf("%d%d",&M,&H);
        ll sum = 0;
        for(int i=1;i<=H;i++){
            ll a,b;
            scanf("%lld%lld",&a,&b);
            sum+=(power(a,b,M)%M);
        }
        printf("%lld\n",sum%M);
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_40772692/article/details/80079298