解题报告
题目 :http://acm.hdu.edu.cn/showproblem.php?pid=3221
(09年上海赛区programB)
题目大意 : f[n] = f[n – 1] * f[n – 2] (f[1] = a; f[2] =b); 求f[n] % p;
算法 :a ^ b % c = a ^(b % phi[c] + phi[c]) % c (b >= phi[c])时, 矩阵快速幂
思路 :f[n] = f[n – 1] * f[n – 2] 即 f[n] = (a^x * b^y) % p; à f[n] = a^x % p * b^y %p %p
è 由乘法的结合率知x,y是斐波纳妾的第ff[n – 2] 和 ff[n – 1]项。
è F[n] = (a^ff[n – 2] % p ) * ( b^ff[n – 1] % p) % p
è F[n] = (a^( ff[n – 2] % phi[p] + phi[p]) % p) * b^( ff[n – 1] % phi[p] + phi[p]) % p) % p )
è 解次表达式即可,其中斐波纳妾数列ff要用矩阵快速幂求
è 要注意的是公式当(b >= phi[c])时才能用,应此前50项左右要用朴素算法。
一直wa在n=1的时候,n=1时输出a%p而不是a!
收获与总结 :再次感受了数论的魅力,太爽了!细心啊。
提交情况 :wrong answer 6次 (第一项出错了)
Accepted 1 次
AC code:
#include <stdio.h>
#include <math.h>
#include <string.h>
typedef __int64 I64;
I64 a, b, n, p, q1, q2;
struct LINE{
I64 line[2];
};
struct ROW{
LINE row[2];
};
I64 Multi(I64 aa, I64 bb, I64 cc){
I64 ans = 0;
while(bb){
if(bb & 1) ans = (ans + aa) % cc;
aa = (aa + aa) % cc;
bb >>= 1;
}
return ans;
}
I64 MOD(I64 aa, I64 bb, I64 cc){
I64 ans = 1;
while(bb){
if(bb & 1) ans = Multi(ans, aa, cc);
aa = Multi(aa, aa, cc);
bb >>= 1;
}
return ans;
}
I64 Getphi(I64 c){
I64 ans = c, i, m;
if(c % 2 == 0){
ans = ans / 2;
while(c % 2 == 0) c /= 2;
}
m = (I64)sqrt((long double)c) + 1;
for(i = 3; i <= m && c >= i; i += 2){
if(c % i) continue;
ans = (ans / i) * (i - 1);
while(c % i == 0) c /= i;
}
if(c != 1) ans = (ans / c) * (c - 1);
return ans;
}
ROW Matrix_Multi(ROW A, ROW B, I64 phip){
int i, j , k;
ROW ans = {0};
for(i = 0; i < 2; i ++)
for(j = 0; j < 2; j ++)
for(k = 0; k < 2; k ++)
ans.row[i].line[j] = (ans.row[i].line[j] + Multi(A.row[i].line[k], B.row[k].line[j], phip)) % phip;
return ans;
}
voidget_F_mod_phi(int m, int phip){
ROW A, temp;
A.row[0].line[0] = 0; A.row[0].line[1] = 1;
A.row[1].line[0] = 1; A.row[1].line[1] = 1;
temp.row[0].line[0] = 1; temp.row[0].line[1] = 0;
temp.row[1].line[0] = 0; temp.row[1].line[1] = 1;
while(m){
if(m & 1) temp = Matrix_Multi(temp, A, phip);
A = Matrix_Multi(A, A, phip);
m >>= 1;
}
q1 = (temp.row[0].line[0] + temp.row[1].line[0]) % phip;
q2 = (temp.row[0].line[1] + temp.row[1].line[1]) % phip;
}
I64 get(){
I64 f[100], ans;
int i;
if(n == 1) return a % p;
if(n == 2) return b % p;
f[1] = f[2] = 1;
for(i = 3; i < n; i ++) f[i] = f[i - 1] + f[i - 2];
ans = Multi(MOD(a, f[n - 2], p), MOD(b, f[n - 1], p), p);
return ans;
}
I64 chap(){
I64 phip;
phip = Getphi(p);
get_F_mod_phi(n - 3, phip);
I64 ans1 = MOD(a, q1 + phip, p);
I64 ans2 = MOD(b, q2 + phip, p);
return Multi(ans1, ans2, p);
}
int main(){
int CASE, T;
I64 ans;
scanf("%d", &CASE);
for(T = 1; T <= CASE; T ++){
scanf("%I64d %I64d %I64d %I64d", &a, &b, &p, &n);
ans = n > 50 ? chap() : get();
printf("Case #%d: %I64d\n", T, ans);
}
return 0;
}