• 快速幂(Fast Pow)


    定义

    快速求a^b%c的算法

    原理

    指数可以被二进制分解

    那么a^b可以分解为a^2^k1*a^2^k2*……

    又显然a^2^(k+1)=a^(2^k*2)=(a^2^k)^2

    所以可以将指数在二进制下从低位向高位递推,每次将底数平方,若该位是1就将答案乘上底数,直到指数为0。

    实现时可以每次将指数/2方便处理

    位运算优化

    x&1:取x二进制下最后一位

    x>>1:x/2

    代码

    int quickpow(int a,int b,const int c)
    {
        int base=a%c,ans=1;
        while(b)
        {
            if(b&1)
                ans=ans*base%c;
            base=base*base%c;
            b>>=1;
        }
        return ans;
    }
    快速幂

    例题

    一、序列的第k个数

    根据元素之差判断是不是等差数列,不是等差数列即为等比数列

    推通项公式时注意序列起始为a

    #include<cstdio>
    #include<cctype>
    using namespace std;
    #define re register int
    #define ll long long
    int stk[111],tt;
    void print(ll x)
    {
        if(x==0)
            putchar('0');
        else
        {
            if(x<0)
                putchar('-'),x=-x;
            tt=0;
            while(x)
            {
                stk[++tt]=x%10;
                x/=10;
            }
            for(re i=tt;i;i--)
                putchar(stk[i]|48);
        }
    }
    int read()
    {
        int x=0,f=0;
        char c=getchar();
        while(!isdigit(c))
        {
            f|=c=='-';
            c=getchar();
        }
        while(isdigit(c))
        {
            x=(x<<3)+(x<<1)+(c^48);
            c=getchar();
        }
        return f?-x:x;
    }
    const int MOD=200907;
    ll quickpow(int a,int b,const int c)
    {
        ll base=a%c,ans=1;
        while(b)
        {
            if(b&1)
                ans=ans*base%c;
            base=base*base%c;
            b>>=1;
        }
        return ans;
    }
    int main()
    {
        int T=read();
        ll a,b,c,k;
        while(T--)
        {
            a=read(),b=read(),c=read(),k=read();
            if(b-a==c-b)
                print((a+(b-a)*(k-1))%MOD);
            else
                print(a*quickpow(b/a,k-1,MOD)%MOD);
            putchar('
    ');
        }
        return 0;
    }
    序列的第k个数

    二、[NOIP2013]转圈游戏

    走10^k轮即移动m*10^k个位置,再加上x取模即可

    #include<cstdio>
    #include<cctype>
    using namespace std;
    #define re register int
    #define ll long long
    int stk[111],tt;
    void print(int x)
    {
        if(x==0)
            putchar('0');
        else
        {
            if(x<0)
                putchar('-'),x=-x;
            tt=0;
            while(x)
            {
                stk[++tt]=x%10;
                x/=10;
            }
            for(re i=tt;i;i--)
                putchar(stk[i]|48);
        }
    }
    int read()
    {
        int x=0,f=0;
        char c=getchar();
        while(!isdigit(c))
        {
            f|=c=='-';
            c=getchar();
        }
        while(isdigit(c))
        {
            x=(x<<3)+(x<<1)+(c^48);
            c=getchar();
        }
        return f?-x:x;
    }
    ll quickpow(int a,int b,const int c)
    {
        ll base=a%c,ans=1;
        while(b)
        {
            if(b&1)
                ans=ans*base%c;
            base=base*base%c;
            b>>=1;
        }
        return ans;
    }
    int main()
    {
        int n=read(),m=read(),k=read(),x=read();
        ll ans=(x+m*quickpow(10,k,n))%n;
        print(ans);
        putchar('
    ');
        return 0;
    }
    转圈游戏

    三、[HNOI2008]越狱

    可越狱方案数不好求,但从容斥原理的角度,答案可以表示成总排列数-不可越狱排列数

    这两个数都很好求,总排列数=m^n,不可越狱排列数考虑第一个数有m种选法,后面每个数都只有m-1种选法,于是=m*(m-1)^(n-1)

    #include<cstdio>
    #include<cctype>
    using namespace std;
    #define re register int
    #define ll long long
    int stk[111],tt;
    void print(int x)
    {
        if(x==0)
            putchar('0');
        else
        {
            if(x<0)
                putchar('-'),x=-x;
            tt=0;
            while(x)
            {
                stk[++tt]=x%10;
                x/=10;
            }
            for(re i=tt;i;i--)
                putchar(stk[i]|48);
        }
    }
    ll read()
    {
        ll x=0;
        int f=0;
        char c=getchar();
        while(!isdigit(c))
        {
            f|=c=='-';
            c=getchar();
        }
        while(isdigit(c))
        {
            x=(x<<3)+(x<<1)+(c^48);
            c=getchar();
        }
        return f?-x:x;
    }
    const int MOD=100003;
    ll quickpow(int a,ll b)
    {
        ll base=a%MOD,ans=1;
        while(b)
        {
            if(b&1)
                ans=ans*base%MOD;
            base=base*base%MOD;
            b>>=1;
        }
        return ans;
    }
    inline int mod(ll a)
    {
        a%=MOD;
        if(a<0)
            a+=MOD;
        return a;
    }
    int main()
    {
        ll m=read(),n=read();
        print(mod(quickpow(m,n)-m*quickpow(m-1,n-1)));
        putchar('
    ');
        return 0;
    }
    越狱

    注意事项

    1、根据题目数据范围适当修改快速幂函数中数据的类型

    2、取模的数可能<0时注意实际意义

  • 相关阅读:
    leetcode刷题四<寻找两个有序数组的中位数>
    leetcode刷题第三天<无重复字符的最长子串>
    leetcode刷题第二天<两数相加>
    leetcode刷题第一日<两数和问题>
    sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError)
    flask微电影系统开发中上下文处理器
    gdb解决字符串打印果断措施
    邻接表
    Jarvis OJ 一些简单的re刷题记录和脚本
    windows控件理论学习
  • 原文地址:https://www.cnblogs.com/LiHaozhe/p/9800409.html
Copyright © 2020-2023  润新知