蓝桥杯 算法提高 JOE的算数 (快速幂取模)

JOE的算数

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
  有一天,JOE终于不能忍受计算a^ b%c这种平凡的运算了。所以他决定要求你写一个程序,计算a^b%c。

提示:若b为奇数,,a^ b=(a^ (b/2))^ 2*a,否则a^ b=(a^ (b/2))^2。
输入格式
  三个非负整数a,b,c;
输出格式
  一个整数ans,表示a^b%c;
样例输入
7 2 5
样例输出
4
数据规模和约定
  30% a <= 100, b <= 10^4, 1 <= c <= 100
  60% a <=10^4, b <= 10^5, 1 <= c <= 10^4
  100% a <=10^6, b <= 10^9, 1 <= c <= 10^6

解题思路
本题是快速幂取模的裸题。
幂指数b可能达到10^9,所以用for循环逐个做乘法肯定会超时,而且运算结果是个天文数字。根据题目给的提示,可以每一次都把b降低一倍,这也就是快速幂算法,可以把时间复杂度降低为O(log n)。
根据数学运算法则,b为偶数时:a^ b=(a^ (b/2))^ 2 =(a^2) ^b/2
b为奇数时: a^ b=((a^ (b/2))^ 2)*a=((a^2) ^b/2) *a
比如
记A为a,则

  1. a ^ 11= A ^ 11=((A^2) ^5) *A 此时 A^2 为新的底数,记为B,11/2=5为新的指数。
  2. ((A^2) ^5)=B ^5=((B ^2) ^2) * B 同理 B ^2 即a ^4 是新的底数,记为C,新的指数是5/2=2
  3. ((B ^2) ^2)=(( C) ^ 2)=((C ^2) ^1) 继续 C ^2 即 a ^8 是新的底数,记为D,新的指数为2/2=1。
  4. ((C ^2) ^1)=((D) ^ 1)=((D ^ 2) ^ 0) * D 此时指数为1/2=0,结束迭代。

即 a ^ 11=A * B * C=a ^1 * a ^ 2 * a ^ 8
从上面可以得到启发:
1.A B C D都各自是前面的平方,所以每一轮迭代用tmp=tmp* tmp 来模拟这个过程。
2*.只有当指数为奇数的时候,末尾才要补乘以底数。(上面已加粗显示)
用二进制很好理解,把b转换为二进制数,二进制每一位的权值都是前一位的两倍,对应着tmp*tmp,例如11(10)=1011(2)=2 ^ 3 +2 ^ 1 + 2 ^ 0 =8 + 2 + 1 。
还要注意取模,根据模运算的性质,得 a ^ b mod c = ((a mod c) ^ b) mod c

#include<stdio.h>
using namespace std;

int main(){
	long long int a,b,c;
	long long int tmp=1;
	long long int result=1;
	scanf("%lld%lld%lld",&a,&b,&c);
	
	tmp=a;	
	while(b){
		if(b&1)			//判断为奇数还是偶数
			result=(tmp*result)%c;
		tmp=(tmp*tmp)%c;
		b=b>>1;			//右移一位,相当于除以二
	}
	printf("%lld",result);
	
	return 0;	
}
发布了17 篇原创文章 · 获赞 2 · 访问量 433

猜你喜欢

转载自blog.csdn.net/Raymond_YP/article/details/104365125