HDU4565 So Easy!
1 /* 2 HDU4565 So Easy! 3 http://acm.hdu.edu.cn/showproblem.php?pid=4565 4 数论 快速幂 矩阵快速幂 5 题意:求[(a+sqrt(b))^n ]%m [ ]代表向上取证 6 联想到斐波那契数列,所以第一感觉是矩阵快速幂 7 后来发现根本不用这么麻烦,我们认为a+b*sqrt(c)中的a为实部 8 b为虚部,就能直接用二元乘法模拟矩阵快速幂了,因此这两种方法 9 是等价的。于是乎,我们就解决了精度问题。 10 然而即使我们得出了结果中的a+b*sqrt(c)也不能这么算 11 因为[b*sqrt(c)]%m不和[b%m*sqrt(c)]%m同余,因此只能另辟蹊径。 12 注意到题目中的(a-1)^2< b < a^2 <=> 0<a-sqrt(b)<1 13 所以 0<(a+sqrt(b))^n<1 而 (a+sqrt(b))^n与(a-sqrt(b))^n是公轭的 14 所以其和只剩下了实部的二倍。因此只需求出实部,将其乘以2就是答案。 15 */ 16 #include <cstdio> 17 #include <algorithm> 18 #include <cstring> 19 #include <cmath> 20 #include <vector> 21 #include <queue> 22 #include <iostream> 23 #include <map> 24 #include <set> 25 #define test 26 using namespace std; 27 const int Nmax=1005; 28 //const long long mod=2147483647LL; 29 //double eps=1e-8; 30 long long a,b,n,m; 31 struct Num 32 { 33 long long a; 34 long long b; 35 long long c; 36 Num(long long _a,long long _b,long long _c) 37 { 38 a=_a; 39 b=_b; 40 c=_c; 41 } 42 friend Num operator * (Num x,Num y) 43 { 44 long long a1=x.a%m,b1=x.b%m,a2=y.a%m,b2=y.b%m,c=x.c; 45 long long a=(a1*a2%m+((c*b1*b2)%m))%m; 46 long long b=((a1*b2)%m+((b1*a2)%m))%m; 47 return Num(a,b,c); 48 } 49 friend Num qpow(Num base,long long n) 50 { 51 Num ans(1LL,0LL,base.c); 52 //ans.print(); 53 while(n>0LL) 54 { 55 if(n&1LL) 56 ans=ans*base; 57 base=base*base; 58 n>>=1; 59 //ans.print(); 60 } 61 //printf("%lld %lld %lld\n",ans.a,ans.b,ans.c); 62 return ans; 63 } 64 void print() 65 { 66 printf("a:%lld b:%lld c:%lld\n",a,b,c); 67 } 68 }; 69 70 void work() 71 { 72 Num base(a,1LL,b); 73 Num ans=qpow(base,n); 74 //ans.print(); 75 long long a=ans.a,b=ans.b,c=ans.c; 76 //long long res=(long long)ceil(a+b*sqrt(c));//不能这么写,因为整数和小数直接不能模 77 //while(a<=0) 78 //a+=m; 79 //while(b<=0) 80 //b+=m; 81 //ans.print(); 82 //long long res=(long long)ceil(a+b*sqrt(c)); 83 //printf("res:%lld\n",res); 84 //res=res%m; 85 //printf("%lld %lld %ll\n",a,b); 86 //ans.print(); 87 //if(2LL*a!=ceil(a+b*sqrt(c))) 88 //printf("NO\n"); 89 //res=(2LL*a)%m; 90 //printf("ans:%lld myans:%lld\n",(2LL*a)%m,(long long)ceil(a+b*sqrt(c))%m); 91 long long res=2LL*a%m; 92 printf("%lld\n",res); 93 94 } 95 int main() 96 { 97 #ifdef test 98 //freopen("hdu4565.in","r",stdin); 99 #endif 100 while(scanf("%lld%lld%lld%lld",&a,&b,&n,&m)==4) 101 work(); 102 return 0; 103 }