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 <= 10^18), You should solve for
g(g(g(n))) mod 10 9 + 7
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
中间矩阵很好求
g(n) = 3g(n - 1) + g(n - 2)
[ g(1) ] * [3 1] = [ g(2) ]
[ g(0) ] [1 0] [ g(1) ]
[ g(1) ] * [3 1] .... * [3 1] (乘了n-1个) = [ g(n) ]
[ g(0) ] [1 0] [1 0] [ g(n-1) ]
若【3 1】的n-1次方为【a b】
【1 0】 【c d】
则g(n) = a*g(1) + b*g(0) = a;
求矩阵幂就行了。
主要是mod的值,题给的是 g(g(g(n))) mod 10^9 + 7,意思是三层mod是10^9 + 7,
里面两层呢???
这就是循环节,举个例子。
a(t) % (10^9 + 7) = 6
a(t+1) % (10^9 + 7) = 7
a(t+2) % (10^9 + 7) = 8
a(t+2) % (10^9 + 7) = 9
…
a(t+x) % (10^9 + 7)=6
这就看出来规律了,a(t+nx) %(10^9 + 7) = 6;
为了防止括号里面的值爆掉,我们只需要让里面的值%x就行了,这样就不会爆掉。
让x1, x2, x3表示三次的mod吧。
x3 = 10^9 + 7;
int main()
{
ll u = 1, v = 0;
for(ll i = 1; i <= 111111111111; i++) //这里的i表示就是g(i)到那了。
{
ll t = ((3*u)%x3 + v%mod) % x3; // 这里是x3
v = u;
u = t;
if(u == 1 && v == 0)
{
x2 = i;
break;
}
}
return 0;
}
这里就求出来一个g( g(g(n)) % x2) % x3;
再求一次
int main()
{
ll u = 1, v = 0;
for(ll i = 1; i <= 111111111111; i++) //这里的i表示就是g(i)到那了。
{
ll t = ((3*u)%x2 + v%mod) % x2; // 这里是x2
v = u;
u = t;
if(u == 1 && v == 0)
{
x2 = i;
break;
}
}
return 0;
}
这里就求出来一个 g( g( g(n) % x1 ) % x2) % x3; 让我们求的就是这个,这两个解得先写个函数算出来,写这个题直接用,x2 = 222222224; x1 = 183120; 要不然光算这就超时了。上代码
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<cstdlib>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define ll long long
const int N = 4;
using namespace std;
struct node
{
ll m[N][N];
}a, res, tmp;
node zhen(node x, node y, ll mod)
{
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++)
tmp.m[i][j] = 0;
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++)
for(int k = 1; k <= 2; k++)
tmp.m[i][j] = (tmp.m[i][j] % mod + ((x.m[i][k] % mod)*(y.m[k][j] % mod))%mod) % mod;
return tmp;
}
void p(node a, ll n, ll mod)
{
for(int i = 1; i <= 2; i++)
for(int j = 1; j <= 2; j++)
res.m[i][j] = 0;
res.m[1][1] = res.m[2][2] = 1;
while(n)
{
if(n&1)
res = zhen(res, a, mod);
a = zhen(a, a, mod);
n>>=1;
}
}
void gg() //初始
{
a.m[1][1] = 3;
a.m[1][2] = 1;
a.m[2][1] = 1;
a.m[2][2] = 0;
}
int main()
{
ll mod = 1000000007;
ll t;
ll x1 = mod;
ll x2 = 222222224;
ll x3 = 183120;
while(cin >> t)
{
if(t == 1 || t == 0)
{
cout << t << endl;
continue;
}
gg();
p(a, t-1, x3);
t = res.m[1][1]%x3;
if(t == 1 || t == 0)
{
cout << t << endl;
continue;
}
gg();
p(a, t-1, x2);
t = res.m[1][1]%x2;
if(t == 1 || t == 0)
{
cout << t << endl;
continue;
}
gg();
p(a, t-1,x1);
t = res.m[1][1]%x1;
cout << t << endl;
}
return 0;
}
“这些年我一直提醒自己一件事情:千万不要自己感动自己。大部分人看似的努力不过是愚蠢导致的,什么熬夜看书到天亮,连续几天就睡几个小时,多久没放假了等等。如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多,人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里 。”
——于宙 《我们这一代人的困惑》