1044:A^B mod C v1.0 (1<=A,B<2^62, 1 <= C <= 10^9)
http://acm.bit.edu.cn/mod/programming/view.php?a=530
1045:A^B mod C v2.0 (1<=A,B,C<2^62)
http://acm.bit.edu.cn/mod/programming/view.php?a=531
1056:A^B mod C v3.0 1<=A,C<=1000000000,1<=B<=10^1000000).
http://acm.bit.edu.cn/mod/programming/view.php?a=542
三题题意相同:求A^B mod C的值,但数据范围不同。
第一题最基础的快速幂无须多言
#include<iostream>
int main()
{
__int64 a,b,c,t;
while(~scanf("%I64d%I64d%I64d",&a,&b,&c))
{
a%=c,t=1;
while(b-1)
{
if(b%2) t=t*a%c;
b/=2,a=a*a%c;
}
printf("%I64d\n",a*t%c);
}
return 0;
}
第二题 C的范围变成了long long ,导致快速幂中将会有两个long long 相乘超long long的情况。
故写一个函数在不超long long的情况下计算 a和b相乘mod c。方法和快速幂一个思路!(快速乘?) 若b为偶数,mul(a,b)=mul(a+a,b/2) 若b为偶数mul(a,b)=mul(a+a,b/2)+a。
把乘法变成加法来做,这样就不会超long long 了=w=
#include<iostream>
__int64 a,b,c,t;
__int64 mul(__int64 a,__int64 b) //a*b%c的二分做法:防止超long long
{
__int64 t=0;
while(b>1)
{
if(b%2) t=(t+a)%c;
a=(2*a)%c,b/=2;
}
return (t+a)%c;
}
int main()
{
while(~scanf("%I64d%I64d%I64d",&a,&b,&c))
{
a%=c,t=1;
while(b-1)
{
if(b%2) t=mul(t,a);
b/=2,a=mul(a,a);
}
printf("%I64d\n",mul(t,a));
}
return 0;
}
第三题更神奇了,B变成了100000位的大数。用高精度计算吃力不讨好(超时),这时又要用到数论结论。幂运算然后取模随着指数的增加是有循环节的,有定理
证明详见http://hi.baidu.com/aekdycoin/item/e493adc9a7c0870bad092fd9
那么就可以用b%phi(c)+phi(c)来代替b做快速幂。如何求大数b%phi(c)呢?如求1234567654321%101,先1模101,然后乘以10再+2,再模,再乘以10再+3,即可。
注意公式中的限制条件x>=phi(c)
#include<iostream>
char b[1000005];
__int64 phi(__int64 a) //求欧拉函数值
{
__int64 ans=a;
for(int i=2;i*i<=a;i++)
{
if(a%i==0)
{
ans=ans/i*(i-1);
while(a%i==0) a/=i;
}
}
if(a>1) ans=ans/a*(a-1);
return ans;
}
int main()
{
__int64 a,c,t,phic,newb,len,i;
while(~scanf("%I64d",&a))
{
bool flag=false; //b是否大于phic
scanf("%s%I64d",b,&c);
a%=c,t=1,phic=phi(c),len=strlen(b),newb=0;
for(i=0;i<len;i++) //求b%phi(c)
{
newb=newb*10+(b[i]-'0');
if(newb>=phic) newb%=phic,flag=true;
}
if(flag==true) newb+=phic; //新的指数为b%phi(c)+phi(c)
while(newb-1)
{
if(newb%2) t=t*a%c;
newb/=2,a=a*a%c;
}
printf("%I64d\n",a*t%c);
}
return 0;
}