hdu 4291 A Short problem (矩阵快速幂+循环节)

Problem Description
  According to a research, VIM users tend to have shorter fingers, compared with Emacs users.
  Hence they prefer problems short, too. Here is a short one:
  Given n (1 <= n <= 1018), You should solve for 
g(g(g(n))) mod 109 + 7

  where
g(n) = 3g(n - 1) + g(n - 2)

g(1) = 1

g(0) = 0
 

Input
  There are several test cases. For each test case there is an integer n in a single line.
  Please process until EOF (End Of File).
 

Output
  For each test case, please print a single line with a integer, the corresponding answer to this case.
 

Sample Input
0
1
2
 

Sample Output
0
1
42837
 
    这题主要找循环节,mo1=1000000007,mo2=222222224,mo3=183120;找到循环节后只要用矩阵快速幂就可以了,下面有找循环节代码。
    由于找循环节很耗时,所以找到后直接写出来,不用写在代码里。
 
 找循环节:
 
 1 #include<cstdio>
 2 long long mo1=1000000007;
 3 int main()
 4 {
 5     long long i=1,a=1,b=0,c;
 6     while (i)
 7     {
 8         c=(3*a+b)%mo1;
 9         b=a;
10         a=c;
11         if (a==1&&b==0)
12         {
13             printf("%I64d
",i);
14             break;
15         }
16         i++;
17     }
18 }
View Code


ac代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 long long mo1=1000000007;
 6 long long mo2=222222224;
 7 long long mo3=183120;
 8 long long s1[3][3],s2[3][3],s3[3][3];
 9 long long f(long long n,long long mo)
10 {
11     int i,j,k;
12     s1[0][0]=s2[0][0]=3;
13     s1[0][1]=s2[0][1]=1;
14     s1[1][0]=s2[1][0]=1;
15     s1[1][1]=s2[1][1]=0;
16     n-=2;
17     while (n)
18     {
19         if (n&1)
20         {
21             memset(s3,0,sizeof(s3));
22             for (k=0;k<2;k++)
23             for (i=0;i<2;i++){if (!s1[i][k]) continue;
24             for (j=0;j<2;j++)
25             s3[i][j]=(s3[i][j]+s1[i][k]*s2[k][j])%mo;}
26             for (i=0;i<2;i++)
27             for (j=0;j<2;j++) s2[i][j]=s3[i][j];
28         }
29         memset(s3,0,sizeof(s3));
30         for (k=0;k<2;k++)
31         for (i=0;i<2;i++) {if (!s1[i][k]) continue;
32         for (j=0;j<2;j++)
33         s3[i][j]=(s3[i][j]+s1[i][k]*s1[k][j])%mo;}
34         for (i=0;i<2;i++)
35         for (j=0;j<2;j++) s1[i][j]=s3[i][j];
36         n>>=1;
37     }
38     return s2[0][0];
39 }
40 int main()
41 {
42     long long n;
43     long long ans;
44     while (~scanf("%I64d",&n))
45     {
46         if (n==0) {printf("0
");continue;}
47         if (n==1) {printf("1
");continue;}
48         ans=f(n,mo3);
49         if (ans>=2) //一定要有,不然ans<2时函数就会死循环。
50         ans=f(ans,mo2);
51         if (ans>=2)
52         ans=f(ans,mo1);
53         printf("%I64d
",ans);
54     }
55 }
原文地址:https://www.cnblogs.com/pblr/p/4759823.html