次方求模 http://acm.nyist.net/JudgeOnline/problem.php?pid=102
次方求模
时间限制: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
- 来源
- [张云聪]原创
- 上传者
- 张云聪
-
#include<stdio.h> long long fun(long long a,long long b,long long c) { long long r=a%c; long long k=1; while(b) { if (b&1) k=(k*r)%c; r=(r*r)%c; b>>=1; } return k; } int main() { int n; scanf("%d",&n); while(n--) { long a,b,c,count; scanf("%d %d %d",&a,&b,&c); count=fun(a,b,c); printf("%d\n",count); } return 0; }
看着代码很简单,可是背后蕴含了多少了汗水啊!看一下算法吧:其实就是a^29=a^14*a,而a^14=a^7*a^7,a^7=a^3*a^3,a^3=a^2*a,这样求a^29就用了7次乘法,不知你有没有发现,这和二分法查找很相似,每次规模都近视减少了一半。注意long long 的使用,否则就会溢出,得不到正确答案。
补充:
利用模运算的运算规则,我们可以使某些计算得到简化。例如,我们想知道3333^5555的末位是什么。很明显不可能直接把3333^5555的结果计算出来,那样太大了。但我们想要确定的是3333^5555(%10),所以问题就简化了。根据运算规则(4)a^b% p = ((a % p)^b) % p ,我们知道3333^5555(%10)= 3^5555(%10)。由于3^4 = 81,所以3^4(%10)= 1。根据运算规则(3) (a * b) % p = (a % p * b % p) % p ,由于5555 = 4 * 1388 + 3,我们得到3^5555(%10)=(3^(4*1388) * 3^3)(%10)=((3^(4*1388)(%10)* 3^3(%10))(%10)=(1 * 7)(%10)= 7。计算完毕。利用这些规则我们可以有效地计算X^N(% P)。简单的算法是将result初始化为1,然后重复将result乘以X,每次乘法之后应用%运算符(这样使得result的值变小,以免溢出),执行N次相乘后,result就是我们要找的答案。这样对于较小的N值来说,实现是合理的,但是当N的值很大时,需要计算很长时间,是不切实际的。下面的结论可以得到一种更好的算法。如果N是偶数,那么X^N =(X*X)^[N/2];如果N是奇数,那么X^N = X*X^(N-1) = X *(X*X)^[N/2];其中[N]是指小于或等于N的最大整数。C++实现功能函数:1234567891011121314151617/*
函数功能:利用模运算规则,采用递归方式,计算X^N(% P)
函数名:PowerMod
输入值:unsigned int x,底数x
unsigned int n,指数n
unsigned int p,模p
返回值:unsigned int,X^N(% P)的结果
*/
unsigned PowerMod(unsigned x , unsigned n , unsigned p)
{
if
(!n)
return
0;
unsigned temp = PowerMod((x * x) % p , n >> 1 , p);
//递归计算(X*X)^[N/2]
if
(n & 1)
//判断n的奇偶性
temp = (temp * x) % p;
return
temp;
}