zoukankan      html  css  js  c++  java
  • 快速幂取模和快乘取模

    一、快速幂取模概念

      快速幂取模,顾名思义,就是快速的求一个幂式的模(余),比如a^b%c,快速的计算出这个式子的值。

      在程序设计过程中,经常要去求一些大数对于某个数的余数,为了得到更快、计算范围更大的算法,产生了快速幂取模算法。

    二、快速幂取模算法实现

     1)很容易能想到,循环b次,每次乘a,最后对c取余就可以了。

    int ans = 1;
    for(int i = 1; i<=b; i++)
    {
        ans = ans * a;
    }
    ans = ans % c;

      这个朴素算法的问题是:

        1.如果a和b都很大,那么ans很有可能超出long long类型,最后结果错误

        2.如果b很大,这样计算会超时。

      所以对这个算法需要改进

     2)有一个很简单的公式如下: 

           

      证明略,由上面公式我们可以对上面算法进行优化

    int ans = 1;
    a = a % c;
    for(int i = 1; i<=b; i++)
    {
        ans = (ans * a) % c;//这里再取了一次余
    }
    ans = ans % c;

      这样就解决了超出long long的问题了,但是时间复杂度还没有降低。

     3)为了解决超时问题,我们可以使用下面的公式,证明略

        

    int ans = 1;
    a = a % c;
    if(b%2==1)
        ans = (ans * a) mod c; //如果是奇数,要多求一步,可以提前算到ans中
    k = (a*a) % c; //我们取a2而不是a
    for(int i = 1; i<=b/2; i++)     
    {
        ans = (ans * k) % c;
    }
    ans = ans % c;

      这样,我们就把时间复杂度降到b/2了,观察上式子,可以发现,当我们令k = (a * a) mod c时,状态已经发生了变化,我们所要求的最终结果即为(k)^b/2 mod c而不是原来的a^b mod c,当下次求(k)^b/2 mod c时,我们可以继续对这个式子记成上面格式,我们发现这个过程是可以重复下去的。

     4)最终我们得到快速幂取模的算法

    int ans = 1;
    a = a % c;
    while(b>0) 
    {
        if(b % 2 == 1)
            ans = (ans * a) % c;
        b = b/2;
        a = (a * a) % c; 
    }

    三、快速幂取模模板

    LL poww(LL a, LL b, LL c)//a^b%c
    {
        LL ans = 1;
        a = a % c;
        while(b>0)
        {
            if(b % 2 == 1)
                ans = (ans * a) % c;
            b = b/2;
            a = (a * a) % c;
        }
        return ans;
    }

     四、快乘取模

     1.概念:

      快速乘法是求两个数相乘,即求解a*b%c,很明显这个不会超时,但是如果当a和b特别大的时候,两个数相乘可能超过long long 范围,所以要使用快速乘法,因为在加法运算的时候不会超,而且可以直接取模,这样就会保证数据超不了了。快速乘法的思想和快速幂的思想一样,快速幂是求一个数的高次幂,快速乘法是求两个数相乘。

     2.算法实现:

      这样的式子和a^b%c很像,所以可以用类似于快速幂取模的方法来做。即,将b写成二进制来看,然后拆开相加(正因为二进制的特殊性,才有快速乘和快速幂的成功),比如下面的例子:

      

    32+16+4=52  (实际操作过程中,每次相加都取模)

    这一过程和快速幂取模非常相似。

     3.模板:

    int multiMod(int a, int b, int c)
    {
        int ans = 0;//注意初始化是0,不是1
        while (b)
        {
            if (b & 1)
                ans=(ans+a)%c;
            a = (a + a) % c;//和快速幂一样,只不过这里是加
            b >>= 1;
        }
        return ans; 
    }
  • 相关阅读:
    【后缀数组】poj2406 Power Strings
    [HNOI 2013]游走
    [HAOI 2008]木棍分割
    [SCOI 2010]传送带
    [SDOI 2010]魔法猪学院
    [Codeforces 235B]Let's Play Osu!
    [SPOJ 10628]Count on a tree
    [ZJOI 2010]count 数字计数
    [SHOI 2008]Debt 循环的债务
    [JSOI 2008]星球大战starwar
  • 原文地址:https://www.cnblogs.com/aiguona/p/7323282.html
Copyright © 2011-2022 走看看