次方求模&同余定理

 1 //a^b mod c=(a mod c)^b mod c很容易设计出一个基于二分的递归算法。
 2 #include
 3 #include
 4 //快速幂算法,数论二分 
 5 long long powermod(int a,int b, int c) //不用longlong就报错,题目中那个取值范围不就在2的31次方内
 6 {
 7     long long t;
 8     if(b==0)  return 1%c;
 9     if(b==1)  return a%c;
10     t=powermod(a,b/2,c);//递归调用,采用二分递归算法,,注意这里n/2会带来奇偶性问题
11     t=t*t%c;//二分,乘上另一半再求模
12     if(b&1)  t=t*a%c;//n是奇数,因为n/2还少乘了一次a
13     return t;
14 }
15 int main()
16 {
17     int n;
18     long long a,b,c;
19     scanf("%d",&n);
20     while(n--)
21     {
22         scanf("%lld%lld%lld",&a,&b,&c);
23         printf("%lld\n",powermod(a,b,c));
24     }
25     system("pause");
26     return 0;
27 }
28          
复制代码

#include
int main()
{
	__int64 fac,p,t,sum;
	//while(scanf("%I64d%I64d",&p,&t)!=EOF&&p!=0&&t!=0)
	
		fac=3673;
		p=9057;
		t=12091;
		//scanf("%I64d%I64d%I64d",&fac,&p,&t);//想自己输入的话这句话加上
		sum=1;
		while(p!=0)
		{
			if(p&1)
			{
				sum*=fac;
				sum%=t;
			}
			p>>=1;
			fac=fac%t*fac%t;
		}
		printf("%I64d\n",sum);
	
	return 0;
}

刚开始用pow函数求次幂,后来发现结果以及参数都为浮点型,我就强行转化为(int)得出的结果不对,看来这种方法不行

一旦遇到高次方连乘,一定要记得快速幂啊,太有用了!!!

2:快速幂取模

快速幂取模就是在O(logn)内求出a^n mod b的值。算法的原理是ab mod c=(a mod c)(b mod c)mod c

因此很容易设计出一个基于二分的递归算法。

心得:这题wa好多次了,找了好久多没发现错误,long long 2^63 大概是 9*10^18,假如999999999*999999999*999999999肯定超过int 64位的长度了,所以一定溢出。

快速幂取模就是在O(logn)内求出a^n mod b的值。算法的原理是ab mod c=(a mod c)(b mod c)mod c 
因此很容易设计出一个基于二分的递归算法。
以下是我的代码,以下代码必须保证输入的是合法的表达式,比如不能出现0^0 mod b:

long exp_mod(long a,long n,long b)
{
long t;
if(n==0) return 1%b;
if(n==1) return a%b;
t=exp_mod(a,n/2,b);
t=t*t%b;
if((n&1)==1) t=t*a%b;
return t;
}
3:高次方求模:

比如a的b次方对c求模
我们可以把b 化为二进制形式看那一位有1
比如b=10101则 a^b=a^(10000)*a^(100)*a^(1)
以函数形式体现:
long long a,b,c;
void han()
{
long long t,s;
for(t=a,s=1;b;b>>=1,t*=t,t%=c)//用b>>=1查看b中1
if(b&1){s*=t;s%=c;}
printf("%lld\n",s%c); 
}

4:据说,矩阵快速幂在递推式优化上相当神奇,而且效率很高。。。

  两矩阵相乘,朴素算法的复杂度是O(N^3)。如果求一次矩阵的M次幂,按朴素的写法就是O(N^3*M)。既然是求幂,不免想到快速幂取模的算法,这里有快速幂取模的介绍,a^b %m 的复杂度可以降到O(logb)。如果矩阵相乘是不是也可以实现O(N^3 * logM)的时间复杂度呢?答案是肯定的。

5:同余幂的思想

求出同余幂bn mod m,其中b,n,m都是比较大的整数。例如取b=12345678,n=456789,直接计算显然是不可行的,可以把n按二进制展开,则n=456789就变成了1101111100001010101,这样每次只需要求b mod m,b2 mod m,... b2^(k-1) mod m,然后把对应位置上的二进制是1的项乘起来,每次乘完后求除m的余数即可,大大降低了计算的复杂度。

伪代码如下:

这里还要用一些同余定理

(a+b)mod m=((a mod m)+(b mod m))mod m;

a*b mod m=(a mod m)*(b mod m) mod m;

a^b mod m=(a mod m)^b mod m;

你可能感兴趣的:(次方求模)