A Short problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1785 Accepted Submission(s): 651
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
矩阵很容易构造
矩阵A
1 0
0 0
递推矩阵B
3 1
1 0
g(n)=A*B^(n-1)的第1行第1列。
现在是一个多重函数在最外层取模,n为10^18,当到最外层取模肯定不可以,这时候就要寻找循环节了。首先是最
外层的模,通过暴力判循环节
long long x3, x1=0,x2=1; long long temp=1000000007; for(long long i=2;;i++) { x3=(3*x2+x1)%temp; if(x3==1&&x2==0) { printf("%I64d\n",i-1); break; } x1=x2; x2=x3; }
求出第2层队222222224 取模,同理第3层对183120取模。
代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; struct matrix { long long ma[3][3]; }; long long mod[3]; matrix multi(matrix x,matrix y,long long m) { matrix ans; memset(ans.ma,0,sizeof(ans.ma)); for(int i=1; i<=2; i++) { for(int j=1; j<=2; j++) { if(x.ma[i][j]) { for(int k=1; k<=2; k++) { ans.ma[i][k]=(ans.ma[i][k]+(x.ma[i][j]*y.ma[j][k])%m)%m; } } } } return ans; } int main() { long long n; while(~scanf("%I64d",&n)) { mod[0]=183120; mod[1]=222222224; mod[2]=1000000007; for(int l=0; l<3; l++) { if(n==0) continue; n=n-1; matrix a; a.ma[1][1]=1; a.ma[1][2]=a.ma[2][1]=a.ma[2][2]=0; matrix b; b.ma[1][1]=3; b.ma[1][2]=1; b.ma[2][1]=1; b.ma[2][2]=0; matrix ans; for(int i=1; i<=2; i++) { for(int j=1; j<=2; j++) { if(i==j) ans.ma[i][j]=1; else ans.ma[i][j]=0; } } while(n) { if(n&1) ans=multi(ans,b,mod[l]); b=multi(b,b,mod[l]); n=n>>1; } n=ans.ma[1][1]; } printf("%I64d\n",n); } return 0; }