A Short problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2955 Accepted Submission(s): 1032
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
题意
给你n求 g ( g ( g ( n ) ) ) m o d 1 0 9 + 7 g(g(g(n))) mod 10^9 + 7 g(g(g(n)))mod109+7的值,其中 g ( x ) = 3 g ( x − 1 ) + g ( x − 2 ) g(x)=3g(x-1)+g(x-2) g(x)=3g(x−1)+g(x−2)
思路
这个问题应该从最外层向里思考,对于 g ( x ) = 3 g ( x − 1 ) + g ( x − 2 ) g(x)=3g(x-1)+g(x-2) g(x)=3g(x−1)+g(x−2)来说对 1 e 9 + 7 1e^9+7 1e9+7取余的话,根据取模和递推方程的特性当再次出现连着的两项是0和1的话那么接下去的项数就会之前的重复了,那我们可以这样考虑因为g(x)出现了循环节那么 g ( x % 循 环 节 ) = g ( x ) g(x\%循环节)=g(x) g(x%循环节)=g(x)由于n的范围是1到1e18所以我们求循环节可以这样求
long long mod1=1e9+7;
long long MAX=1e18;
int main()
{
long long a=0;
long long b=1;
for(long long i=2;i<MAX;i++)
{
long long temp=(3*b%mod+a%mod)%mod;
a=b;
b=temp;
if(a==0&&b==1)
{
printf("%d\n",i-1);
break;
}
}
return 0;
}
找出的循环节为
222222224
222222224
222222224
我们知道了第一个
g
(
x
)
g(x)
g(x)中的x是以
222222224
222222224
222222224为循环节的也就是里面的x对
222222224
222222224
222222224有重复,原题套了3层那么第二层就是
g
(
g
(
x
)
)
g(g(x))
g(g(x)),由于外层的g(x)中x也就是现在的g(x)对
222222224
222222224
222222224有重复那么我们可以同样的找一下g(x)对222222224的重复得到为
183120
183120
183120
long long mod1=1e9+7;
long long mod2=222222224;
long long MAX=1e18;
int main()
{
long long a=0;
long long b=1;
for(long long i=2;i<MAX;i++)
{
long long temp=(3*b%mod2+a%mod2)%mod2;
a=b;
b=temp;
if(a==0&&b==1)
{
printf("%d\n",i-1);
break;
}
}
return 0;
}
同样的找一下最后一层的循环节得到240
long long mod1=1e9+7;
long long mod2=222222224;
long long mod3=183120;
long long MAX=1e18;
int main()
{
long long a=0;
long long b=1;
for(long long i=2;i<MAX;i++)
{
long long temp=(3*b%mod3+a%mod3)%mod3;
a=b;
b=temp;
if(a==0&&b==1)
{
printf("%d\n",i-1);
break;
}
}
return 0;
}
那么当他给我们n的时候我们可以从最里面一层一次对其取余得到最外层的x
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <math.h>
#define MAX 2
using namespace std;
long long mod1=1e9+7;
long long mod2=222222224;
long long mod3=183120;
typedef struct {
long long m[MAX][MAX];
}Matrix;
Matrix P={3,1,1,0};
Matrix I={1,0,0,1};
Matrix Matrixmul(Matrix a,Matrix b,long long mod)
{
int i,j,k;
Matrix c;
for(i=0;i<MAX;i++)
for(j=0;j<MAX;j++)
{
c.m[i][j]=0;
for(k=0;k<MAX;k++)
{
c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
}
c.m[i][j]%=mod;
}
return c;
}
Matrix quickpow(long long n,long long mod)
{
Matrix m=P,b=I;
while(n>0)
{
if(n%2==1)
b=Matrixmul(b,m,mod);
n=n/2;
m=Matrixmul(m,m,mod);
}
return b;
}
int main()
{
long long n;
while(scanf("%lld",&n)!=EOF)
{
if(n==0)
{
printf("0\n");
continue;
}
n%=240;
if(n==0)
{
printf("0\n");
continue;
}
Matrix A=quickpow(n-1,mod3);
n=A.m[0][0]%mod3;
if(n==0)
{
printf("0\n");
continue;
}
A=quickpow(n-1,mod2);
n=A.m[0][0]%mod2;
if(n==0)
{
printf("0\n");
continue;
}
A=quickpow(n-1,mod1);
printf("%lld\n",A.m[0][0]%mod1);
}
return 0;
}