Processing math: 100%

Solução Avançado Informática - Semana 37

Solução

Para esse problema vamos primeiro achar uma recursão que represente o problema:

  • fx=fx1+fx2+1
  • f1=1
  • f0=1

Pois para cada valor de fibonacci, temos que a quantidade de chamadas recursivas é igual a quantidade de x1 mais x2 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=2fibx1:

Podemos verificar para os casos bases que isso é verdade:

  • f0=2fib01f0=211=1
  • f1=2fib11f1=211=1

Para o caso geral temos que:

fx=fx1+fx2+1fx=(2fibx11)+(2fibx21)+1fx=2(fibx1+fibx2)1fx=2fibx1

Provando assim por indução que fx=2fibx1.

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=Mc1Mc2 ... 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:


#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;
}

view raw

fib.cpp

hosted with ❤ by GitHub