HDOJ 5667 Sequence//费马小定理 矩阵快速幂
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5667
题意:如题给了一个函数式,给你a,b,c,n,p的值,叫你求f(n)%p的值
思路:先对函数取以a为底的log,令g(n)=log(a)(f(n)),结果就能得到
g(n)=b+c*g(n-1)+g(n-2);(n>3)
g(n)=0;(n=1)
g(n)=b;(n=2)
g(n) c 1 1 g(n-1)
用矩阵表示出来就是 g(n-1) = 1 0 0 * g(n-2)
b 0 0 1 b
设中间的矩阵为A 那么要求g(n)就是用A^(n-2)*g(2)来求得
g(1)
b
而我们要求的是 f(n)%p,f(n)=a^g(n),很明显g(n)是会爆的,那么因为p是质数,所以f(n)%p=(a^(g(n)%(p-1))%p
用快速幂一样的思路来模拟矩阵的乘法就行了
矩阵的乘法三个for循环就能写掉
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]);
然后设置三个矩阵,一个初始化为单位矩阵用来存储答案,一个存储当前的值,一个用来计算。
之后求出了g(n)的值之后,对原式还是要做一次快速幂,注意特判a%p==0的情况,0^0=1不处理
1 #include <stdio.h> 2 #include <iostream> 3 #include <string.h> 4 #include <stdlib.h> 5 #include <algorithm> 6 #include <vector> 7 #include <math.h> 8 using namespace std; 9 long long x[10][10]; 10 long long y[10][10]; 11 long long t; 12 long long n,a,b,c,p; 13 long long qpow1(long long a1,long long n1 ) 14 { 15 long long ans=1; 16 while(n1) 17 { 18 if(n1&1) 19 ans=ans*a1%p; 20 a1=a1*a1%p; 21 n1>>=1; 22 } 23 return ans; 24 } 25 void qpow(long long n1) 26 { 27 long long tmp[10][10]; 28 memset(x,0,sizeof(x)); 29 for(int i=0;i<3;i++) 30 x[i][i]=1; 31 32 while(n1) 33 { 34 memset(tmp,0,sizeof(tmp)); 35 if(n1&1) 36 { 37 for(int i=0;i<3;i++) 38 { 39 for(int j=0;j<3;j++) 40 { 41 for(int k=0;k<3;k++) 42 { 43 tmp[i][j]=(tmp[i][j]+x[i][k]*y[k][j]) % (p-1); 44 } 45 } 46 } 47 for(int i=0;i<3;i++) 48 for(int j=0;j<3;j++) 49 x[i][j]=tmp[i][j]; 50 } 51 memset(tmp,0,sizeof(tmp)); 52 for(int i=0;i<3;i++) 53 { 54 for(int j=0;j<3;j++) 55 { 56 for(int k=0;k<3;k++) 57 { 58 tmp[i][j]=(tmp[i][j]+y[i][k]*y[k][j]) % (p-1); 59 } 60 } 61 } 62 for(int i=0;i<3;i++) 63 for(int j=0;j<3;j++) 64 y[i][j]=tmp[i][j]; 65 n1>>=1; 66 } 67 } 68 int main() 69 { 70 scanf("%lld",&t); 71 while(t--) 72 { 73 scanf("%lld %lld %lld %lld %lld",&n,&a,&b,&c,&p); 74 if(a%p==0) 75 { 76 printf("0\n"); 77 continue; 78 } 79 memset(y,0,sizeof(y)); 80 y[0][0]=c,y[0][1]=1,y[0][2]=1; 81 y[1][0]=1,y[1][1]=0,y[1][2]=0; 82 y[2][0]=0,y[2][1]=0,y[2][2]=1; 83 qpow(n-2); 84 long long ans1=(x[0][0]*b+b*x[0][2])%(p-1); 85 printf("%lld\n",qpow1(a,ans1)); 86 } 87 return 0; 88 }