提起 a^b%c 我们自然想起了模重复平方发,一个可以在 log(n)的时间复杂度内求出他的解。
但是有些情况是不能这样简单的计算的:
情况1:c 很大(c > =2^32)虽可在__int64 的表示范围内,但是如果两个这样的数平方必定会超过__int64的表示范围,就不能简单的乘了,这样可以有两种方法
方法一:如果可以分解为若干个互素的数(利用素数分解),且每个数小于 2^32,可以分别对每个数求出a^b % (这个数)的值,然后建立如干个同余方程,利用中国剩余定理求解最终的答案。
我出的地大的题目。
方法二:对于小于2^63的c,我们可以采用类似于模重复平方法的方法进行乘法。将其中的一个数变为二进制,另外的一个数和这个数相乘就等同于与这个数各个二进制位中每一位相乘然后再相加。
unsigned long long mul(unsigned long long x,unsigned long long y,unsigned long long z)
{
unsigned long long anw,temp;
x = x % z; y = y % z;
if(x < y){temp = x,x = y,y = temp;}
anw = 0;
while(y)
{
if(y%2 == 1) anw = (anw + x)%z;
x = (x * 2)%z;
y = y / 2;
}
return anw;
}
相关题目:福州大学OJ的1752 acm.fzu.edu.cn/problem.php
情况二:当b很大时,并且是用字符串表示,这时可以利用欧拉函数,a^欧拉函数 == 1 mod(m),其中a与m互素。将b缩小到c的欧拉函数的范围之内。(a 与 m 要互素的,如果不互素我感觉可以使用中国剩余定理,将m分解成两部分,一部分互素,一部分为a与m的最大公因素)
相关题目:福州大学OJ1759 acm.fzu.edu.cn/problem.php
#include "stdio.h"
#include "string.h"
int prime[10000],N;
void table()
{
int i,j;
bool hash[31625];
memset(hash,0,sizeof(hash));
for(i = 2; i < 179;i ++)
if(hash[i] == 0)
for(j = i * i ; j < 31624; j = j + i)
hash[j] = 1;
for(i = 2; i < 31624;i++)
if(hash[i] == 0)
prime[N++] = i;
}
int euler(int m)
{
int anw = m,p[35];
for(i = 0,j = 0;i < N&&n!=1 ;i++)
if(a%prime[i] == 0)
{
p[j] = prime[i];
while(n%prime[i]==0)
n = n / prime[i];
j++;
}
if( n!=1 )
{
p[j] = a;
j++;
}
for(i = 0 ;i < j; i++)
{
anw = anw / p[i] * (p[i] - 1) ;
}
return anw;
}
char ch[1000005];
int mod(int m)
{
int i,j,k,temp = 0;
for(i = 0;ch[i] != 0 ;i++)
{
temp = temp * 10 + ch[i] - '0';
if(temp > m)
temp = temp % m;
}
}
附加情况一: a^b%c 当b = b1*b2*b3*b4*b5*b6...时
a^b = (((((a^b1)^b2)^b3)^b4)^b5)