次方求模
时间限制:1000 ms | 内存限制:65535 KB
难度:3
描述
求a的b次方对c取余的值
输入
第一行输入一个整数n表示测试数据的组数(n<100)
每组测试只有一行,其中有三个正整数a,b,c(1=<a,b,c<=1000000000)
输出
输出a的b次方对c取余之后的结果
样例输入
3
2 3 5
3 100 10
11 12345 12345
样例输出
3
1
10481
来源
上传者
快速幂取模的思路:快速幂实现的最基本的理论就是我们离散课上或者数论中学过的一条公式推出的引理。
引理:积的取余等于取余的积的取余。
再在这条引理的基础之上,对指数型数据进行拆分以及合并,从而得到我们用的快速幂算法。
本文我就不用例题讲解,直接对快速幂进行解析。毕竟快速幂的算法相对简单,而且适用题型较为一致。
快速幂具体分析:对a^b进行分析。
对于当a和b较小是直接用int或者long存是没有问题的,但是当a和b大到一定程度时,这就不是暴力存就
可以解决的问题了。我们应该怎么去解决这个问题呢?
在这里我们需要把注意力放在“大”字上面,正是由于a和b过大才导致的问题。所以我们要想办法不断地减
//①a是底数,b是指数,mode是取模数,sum是记录取模的结果
int sum = 1;
a = a % mode;
for(int i = 1; i <= b; i++)
{
sum = sum * a;
}
sum = sum % c;
小a和b的规模,所谓逐个击破。
根据上面的那条引理,我们知道了可以把指数拆开,从这个突破口突破。这里我们就不难想到这样一个算法
这是直接利用的 引理而写出来的代码,这只是单纯的降低的a的规模,但是这还达不到我们的要求,所以我们
需要进一步改进算法。(当然还可以继续降低啊的规模,即将循环中的那句换成sum = (sum * a)%mode)
我们已经实现的降低a的规模,所谓我们要想着怎么降低b的规模。我们首先看两个样例:先看b为偶数的样例
7^16,mode = 3,我们要怎么进行拆分?
最基本的拆分是这样的:7*7*7*7*7*7*7*7*7......7,上面的算法只是将其变为2*2*2*2*2*2*2......2,那么怎么减少b
的规模呢?你应该有一点感觉了吧。就是两两合并,将(7^16)变成(49^8),这就降低了b的规模,再利用上面
的算法降低a的规模,最终会变成1 *1*1*1*1*1*1*1。是不是感觉整个数简单了很多。
按照这个思路,我们可以多循环几次,从而不断的降低a和b的规模。
那么b为奇数怎么办呢?
其实也很简单,我们只要在偶数算法的基础之上,每次把多出来的这个数跳出来,预先取模再带入即可。
从而最终得出快速幂的代码:
#include<stdio.h>
long long powmod(long long a,long long b,long long c)
{
int sum=1;
a = a % c;
while (b>0)
{
if (b%2==1) //判断是否是奇数,是奇数的话将多出来的数事先乘如sum
sum = (sum*a) % c;
b /= 2;
a = (a*a) % c; // 不断的两两合并再取模,减小a和b的规模
}
return sum;
}
int main()
{
int n;
long long a,b,c;
scanf("%d",&n);
while (n--)
{
scanf("%lld %lld %lld",&a,&b,&c);
printf("%lld\n",powmod(a,b,c));
}
return 0;
}