2013寒假练习 快速幂三弹连发 A^B mod C v1.0-3.0

来源:互联网 发布:电子书在线制作软件 编辑:程序博客网 时间:2024/04/30 14:17

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是否大于phicscanf("%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;}