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 }
View Code

 

posted @ 2016-04-27 10:31  as3asddd  阅读(189)  评论(0编辑  收藏  举报