次方求模 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++实现功能函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
函数功能:利用模运算规则,采用递归方式,计算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;
}
posted @ 2013-08-20 17:14  王莜轩  阅读(348)  评论(0编辑  收藏  举报