Solução
Para esse problema vamos primeiro achar uma recursão que represente o problema:
- fx=fx−1+fx−2+1
- f1=1
- f0=1
Pois para cada valor de fibonacci, temos que a quantidade de chamadas recursivas é igual a quantidade de x−1 mais x−2 mais o dele mesmo 1.
Agora já poderíamos montar uma matriz 3x3 e resolver o problema com exponenciação rápida, porém podemos deixar o problema mais simples por meio de matemática.
Vamos partir da hipótese que fx=2⋅fibx−1:
Podemos verificar para os casos bases que isso é verdade:
- f0=2⋅fib0−1⇒f0=2⋅1−1=1
- f1=2⋅fib1−1⇒f1=2⋅1−1=1
Para o caso geral temos que:
fx=fx−1+fx−2+1⇒fx=(2⋅fibx−1−1)+(2⋅fibx−2−1)+1⇒fx=2⋅(fibx−1+fibx−2)−1⇒fx=2⋅fibx−1
Provando assim por indução que fx=2⋅fibx−1.
Para calcular fibx podemos usar o fato que dado uma matriz M=[1110], considerando A=Mn sendo n o n-ésimo número de Fibonacci, temos que fibn=A1,1=(Mn)1,1.
Com isso podemos calcular Mn usando a representação em binário de n, pois Mn=Mc1+c2+ ... ck=Mc1⋅Mc2 ... Mck sendo c1 as potências de dois que compôem n, com isso usando essa técnica podemos aplicar a mesma idéia em matrizes, e é claro computando sempre os elementos módulo b.
Código:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
typedef unsigned long long ull; | |
struct mat | |
{ | |
ull m[2][2]; | |
mat operator* (const mat &rhs) const | |
{ | |
mat ans = {0, 0, 0, 0}; | |
for (int i = 0; i < 2; i++) { | |
for (int j = 0; j < 2; j++) { | |
for (int k = 0; k < 2; k++) { | |
ans.m[i][j] += m[i][k]*rhs.m[k][j]; | |
} | |
} | |
} | |
return ans; | |
} | |
mat operator% (ull x) const | |
{ | |
mat ans = {0, 0, 0, 0}; | |
for (int i = 0; i < 2; i++) { | |
for (int j = 0; j < 2; j++) { | |
ans.m[i][j] = m[i][j]%x; | |
} | |
} | |
return ans; | |
} | |
}; | |
mat power(mat x, ull b, ull mod) | |
{ | |
mat ans = {1, 0, 0, 1}; | |
while (b) { | |
if (b&1ull) ans = (ans*x) % mod; | |
x = (x*x) % mod; | |
b >>= 1; | |
} | |
return ans; | |
} | |
int main() | |
{ | |
ull n, b; | |
cin >> n >> b; | |
mat fib = {1, 1, 1, 0}; | |
fib = power(fib, n, b); | |
ull ans = 2ull*fib.m[0][0] - 1; | |
ans %= b; | |
cout << ans << "\n"; | |
return 0; | |
} |