快速幂算法——人见人爱A^B

 

 http://acm.nefu.edu.cn/problemShow.php?problem_id=444 

这个是原题,大家可以做一下,提交一下。

这个如果用循环,直接生硬去解,如果是很大的数据,一定会超出时间限制。(如果是1000的1000次方,这个数据就很庞大,所以生解一定会爆)

因此我们用一种叫做快速幂运算的算法来解答。

下面提供一下快速幂运算的模板。(这个方法很实用,也好理解,希望大家能了解一下)

 
 3 ^10=3*3*3*3*3*3*3*3*3*3
尽量想办法把指数变小来,这里的指数为10
3^10=(3*3)*(3*3)*(3*3)*(3*3)*(3*3) 3^10=(3*3)^5 3^10=9^5 此时指数由10缩减一半变成了5,而底数变成了原来的平方,求3^10原本需要执行10次循环操作,求9^5却只需要执行5次循环操作,
但是3^10却等于9^5,我们用一次(底数做平方操作)的操作减少了原本一半的循环量,
特别是在幂特别大的时候效果非常好,例如2^10000=4^5000,底数只是做了一个小小的平方操作,而指数就从10000变成了5000,
减少了5000次的循环操作。 现在我们的问题是如何把指数5变成原来的一半,5是一个奇数,5的一半是2.5,但是我们知道,指数不能为小数,
因此我们不能这么简单粗暴的直接执行5/2,然而,这里还有另一种方法能表示9^5 9^5=(9^4)*(9^1)
此时我们抽出了一个底数的一次方,这里即为9^1,这个9^1我们先单独移出来,剩下的9^4又能够在执行“缩指数”操作了,把指数缩小一半,底数执行平方操
9^5=(81^2)*(9^1) 把指数缩小一半,底数执行平方操作 9^5=(6561^1)*(9^1) 此时,我们发现指数又变成了一个奇数1,按照上面对指数为奇数的操作方法,应该抽出了一个底数的一次方,这里即为6561^1,
这个6561^1我们先单独移出来,但是此时指数却变成了0,也就意味着我们无法再进行“缩指数”操作了。 9^5=(6561^0)*(9^1)*(6561^1)=1*(9^1)*(6561^1)=(9^1)*(6561^1)=9*6561=59049
我们能够发现,最后的结果是9*6561,而9是怎么产生的?是不是当指数为奇数5时,此时底数为9。那6561又是怎么产生的呢?
是不是当指数为奇数1时,此时的底数为6561。所以我们能发现一个规律:最后求出的幂结果实际上就是在变化过程中所有当指数为奇数时底数的乘积。
int f(int a,int b,int mod)//a表示底数,b表示指数,mod表示取余(取模)(如3的2次方的后三位数,a就是3,b就是2,1000是mod。3的2次方是9,对1000取模是9,所以答案是9)
{
  int s=1;
  while(b>0)
  {
      if(b%2==1) 
      {
          s=s*a%mod;
          b=b-1;
      }
      else
      {
          a=a*a%mod;
          b=b/2;
      }
  }
  return s;
}

 

 

因此,直接上代码

#include <bits/stdc++.h>
using namespace std;
int f(int a,int b,int mod)
{
  int s=1;
  while(b>0)
  {
      if(b%2==1) 
      {
          s=s*a%mod;
          b=b-1;
      }
      else
      {
          a=a*a%mod;
          b=b/2;
      }
  }
  return s;
}
int main()
{
    int a,b,m;
    while(cin>>a>>b&&a!=0&&b!=0)
    {
        m=f(a,b,1000);
        printf("%d\n",m);
    }
    return 0;
}

 

posted @ 2020-02-08 20:31  剑枫  阅读(369)  评论(0编辑  收藏  举报