首页 > 代码库 > HDU5667—Sequence(对数转化)

HDU5667—Sequence(对数转化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5667

题目意思:f1=1,i=1

     f2=2 ,i=2

     fi=a^b*f[i-1]^c*f[i-2] i>2

思路:发现a^b,和f[i-1]^c之类的东西,我们很明显吧这个幂变成乘,很自然的想到对数。问题是对什么取对数,最后发现对a取对数是合适的。

loga(fi)=loga(a^b*f[i-1]^c*f[i-2])=loga(a^b)+loga(f[i-1]^c)+loga(f[i-2]),我们设k[i]=loga(fi),所以k[i]=b+c*k[i-1]+k[i-2]。我们可以通过矩阵快速幂算出k[n],然后a^k[n]=f[n],可以直接用快速幂算出。

这里需要注意一下,这里需要规避a%p=0的情况,需要先把k[n]%(mod-1),这一点我目前还没办法证明,在完成矩阵快速幂专题以后,研究数论的时候,可能会对这个进一步研究和证明。

代码:

技术分享
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <cmath>
 6 using namespace std;
 7 #define LL long long
 8 LL p,aa,bb,cc,n,mod; //mod为p-1
 9 struct matrix
10 {
11     LL mat[3][3];
12 };
13 matrix pow1(matrix a,matrix b) // N^3的矩阵相乘
14 {
15     matrix c;
16     memset(c.mat,0,sizeof(c.mat));
17     for(int i=0;i<3;i++){
18         for(int j=0;j<3;j++){
19             for(int k=0;k<3;k++){
20                 c.mat[i][j] += (a.mat[i][k]*b.mat[k][j]);
21                 c.mat[i][j] %= mod;
22             }
23         }
24     }
25     return c;
26 }
27 matrix cheng(matrix a,LL y) //矩阵快速幂
28 {
29     matrix b;
30     memset(b.mat,0,sizeof(b.mat));
31     for(int i=0;i<3;i++) b.mat[i][i] = 1;
32     while(y){
33         if(y&1){
34             b = pow1(a,b);
35             y-=1;
36         }else {
37             a = pow1(a,a);
38             y/=2;
39         }
40     }
41     return b;
42 }
43 LL quick_pow(LL a,LL tmp) //对a进行快速幂
44 {
45     LL b = 1ll;
46     while(tmp)
47     {
48         if(tmp&1) b=(a*b)%p;
49         a=(a*a)%p;
50         tmp>>=1;
51     }
52     return b;
53 }
54 int main()
55 {
56     int t;
57     scanf("%d",&t);
58     while(t--){
59         scanf("%lld%lld%lld%lld%lld",&n,&aa,&bb,&cc,&p);
60         matrix ma;
61         mod = p-1;
62         memset(ma.mat,0,sizeof(ma.mat));//初始化递归矩阵
63         ma.mat[0][0] = cc; ma.mat[0][1] = 1; ma.mat[0][2] = bb;
64         ma.mat[1][0] = 1; ma.mat[2][2] = 1;
65 
66 
67         ma = cheng(ma,n-2); //算指数和直接幂有点不同
68         LL tmp = ma.mat[0][0]*bb + ma.mat[0][2]; //取出指数
69         LL ans = quick_pow(aa,tmp);
70         printf("%lld\n",ans);
71 
72     }
73     return 0;
74 }
View Code

 

HDU5667—Sequence(对数转化)