Fibonaççi hərarəti#12483

Fibonaççi hərarəti (Həll təhlili)

ədədi 10^{18}-ə qədər ola bildiyindən Fibonaççi ədədlərini bir-bir hesablamaq mümkün deyil. Matris üsulu da yaramır: -cı qüvvətlərin cəmi üçün ölçüsü təxminən olan matris lazım olardı, isə 10^5-ə qədər ola bilər. Buna görə Fibonaççi ədədləri üçün açıq düsturdan — Bine düsturundan istifadə edək:

f_i = \frac{\varphi^i - \psi^i}{\sqrt{5}},

burada

\varphi = \frac{1 + \sqrt{5}}{2}, \quad \psi = \frac{1 - \sqrt{5}}{2}

və ədədləri x^2 = x + 1 tənliyinin kökləridir və Viyet teoreminə görə \varphi\psi = -1.

Qüvvətin açılışı. Bine düsturunu qüvvətinə yüksəldək və Nyuton binomuna görə mötərizələri açaq:

f_i^k = \frac{(\varphi^i - \psi^i)^k}{(\sqrt{5})^k} = \frac{1}{(\sqrt{5})^k}\sum_{j=0}^{k}(-1)^j C_k^j\, \varphi^{i(k-j)}\psi^{ij} = \frac{1}{(\sqrt{5})^k}\sum_{j=0}^{k}(-1)^j C_k^j\, \left(\varphi^{k-j}\psi^j\right)^i

İşarə edək:

t_j = \varphi^{k-j}\psi^j, \quad j = 0, 1, \ldots, k

üzrə -dən -ə qədər cəmləyək və cəmləmə sırasını dəyişək:

S = \sum_{i=1}^{n} f_i^k = \frac{1}{(\sqrt{5})^k}\sum_{j=0}^{k}(-1)^j C_k^j \sum_{i=1}^{n} t_j^{\,i}

Beləliklə, toplananın cəmi k + 1 toplananın cəminə gətirildi.

Həndəsi silsilə. Daxili cəm vuruğu t = t_j olan həndəsi silsilənin cəmidir:

G(t) = \sum_{i=1}^{n} t^i = \begin{cases} \dfrac{t\,(t^n - 1)}{t - 1}, & t \neq 1, \\[2mm] n, & t = 1 \end{cases}

t = 1 halı həqiqətən yaranır və ayrıca emal tələb edir (əks halda sıfıra bölmə baş verər). Məsələn, ədədi -ə bölünərsə, j = k / 2 olduqda alırıq:

t_{k/2} = (\varphi\psi)^{k/2} = (-1)^{k/2} = 1

t^n qüvvəti binar qüvvətə yüksəltmə üsulu ilə O(\log n) vaxtda hesablanır, buna görə hər toplanan hətta n = 10^{18} olduqda da tez tapılır.

Vuruqların ardıcıl hesablanması. Hər üçün və ədədlərini yenidən qüvvətə yüksəltməyə ehtiyac yoxdur. Qonşu vuruqlar aşağıdakı münasibətlə bağlıdır:

t_{j+1} = t_j \cdot \frac{\psi}{\varphi},

buna görə t_0 = \varphi^k qiymətini bir dəfə hesablamaq, sonra isə hər iterasiyada cari qiyməti -yə vurmaq kifayətdir.

Modul üzrə hesablamalar. Həqiqi ədədlər arifmetikası burada yaramır: p = 10^9 + 7 modulu üzrə dəqiq cavab lazımdır. a + b\sqrt{5} şəklində ədədlərlə işləyəcəyik, burada və — modulu üzrə qalıqlardır. Belə ədədlərin toplanması və vurulması aşağıdakı qaydalarla aparılır:

(a + b\sqrt{5}) + (c + d\sqrt{5}) = (a + c) + (b + d)\sqrt{5}, \\ (a + b\sqrt{5})(c + d\sqrt{5}) = (ac + 5bd) + (ad + bc)\sqrt{5}

a + b\sqrt{5} şəklində ədədlər \mathbb{Z}_p[\sqrt{5}] meydanını əmələ gətirir. Bu meydanda sıfırdan fərqli istənilən elementin tərsi var:

(a + b\sqrt{5})^{-1} = \frac{a - b\sqrt{5}}{a^2 - 5b^2},

həm də a^2 - 5b^2 məxrəci modulu üzrə sıfıra bərabər deyil. Bu, həlldəki bütün bölmələrin düzgünlüyünə təminat verir. və düsturlarında -yə bölmə 2^{-1} \bmod p = (p + 1) / 2 ədədinə vurma ilə əvəz olunur.

2-nin tərs elementi. modulu üzrə -nin tərs elementi elə ədədidir ki, 2x \equiv 1 \pmod{p}.

x = (p + 1) / 2 ədədinin uyğun gəldiyini yoxlayaq:

Deməli, (p + 1) / 2 məhz 2^{-1} \bmod p-dir.

Axtarılan cəm tam ədəddir, buna görə yekun a + b\sqrt{5} qiymətində əmsalı mütləq sıfır olacaq, cavab isə olacaq.

Nümunə

Birinci nümunəyə baxaq: , \boldsymbol{k = 1}. k = 1 olduqda düstur aşağıdakı şəkli alır:

S = \frac{1}{\sqrt{5}}\left(\sum_{i=1}^{4}\varphi^i - \sum_{i=1}^{4}\psi^i\right)

\varphi^2 = \varphi + 1 münasibətindən istifadə edərək -nin qüvvətlərini hesablayaq:

\varphi = \frac{1 + \sqrt{5}}{2}, \quad \varphi^2 = \frac{3 + \sqrt{5}}{2}, \quad \varphi^3 = \frac{4 + 2\sqrt{5}}{2}, \quad \varphi^4 = \frac{7 + 3\sqrt{5}}{2}

Onların cəmi \dfrac{15 + 7\sqrt{5}}{2}-yə bərabərdir. -nin qüvvətləri \sqrt{5}-in -\sqrt{5} ilə əvəz edilməsindən alınır, buna görə onların cəmi \dfrac{15 - 7\sqrt{5}}{2}-yə bərabərdir. Deməli,

S = \frac{1}{\sqrt{5}}\left(\frac{15 + 7\sqrt{5}}{2} - \frac{15 - 7\sqrt{5}}{2}\right) = \frac{7\sqrt{5}}{\sqrt{5}} = 7,

bu da cavabla üst-üstə düşür: 1 + 1 + 2 + 3 = 7.

Nümunəyə baxaq: \boldsymbol{k = 3}. Fərqin kubunu açaq:

f_i^3 = \frac{(\varphi^i - \psi^i)^3}{(\sqrt{5})^3} = \frac{\varphi^{3i} - 3\varphi^{2i}\psi^i + 3\varphi^i\psi^{2i} - \psi^{3i}}{5\sqrt{5}}

Silsilələrin vuruqları (\varphi\psi = -1 bərabərliyindən istifadə edirik):

t_0 = \varphi^3, \quad t_1 = \varphi^2\psi = -\varphi, \quad t_2 = \varphi\psi^2 = -\psi, \quad t_3 = \psi^3

Onda

\sum_{i=1}^{n} f_i^3 = \frac{1}{5\sqrt{5}}\left(\sum_{i=1}^{n}(\varphi^3)^i - 3\sum_{i=1}^{n}(-\varphi)^i + 3\sum_{i=1}^{n}(-\psi)^i - \sum_{i=1}^{n}(\psi^3)^i\right)

Dörd cəmin hər biri həndəsi silsilənin cəmi düsturu ilə hesablanır. Bunu n = 3 üçün yoxlayaq. -nin qüvvətləri:

\varphi^3 = 2 + \sqrt{5}, \quad \varphi^6 = 9 + 4\sqrt{5}, \quad \varphi^9 = 38 + 17\sqrt{5}

Onda

\sum_{i=1}^{3}(\varphi^3)^i = \varphi^3 + \varphi^6 + \varphi^9 = (2 + \sqrt{5}) + (9 + 4\sqrt{5}) + (38 + 17\sqrt{5}) = 49 + 22\sqrt{5}, \\ \sum_{i=1}^{3}(-\varphi)^i = -\varphi + \varphi^2 - \varphi^3 = \frac{-(1 + \sqrt{5}) + (3 + \sqrt{5}) - (4 + 2\sqrt{5})}{2} = -1 - \sqrt{5}

üçün cəmlər \sqrt{5}-in -\sqrt{5} ilə əvəz edilməsindən alınır:

\sum_{i=1}^{3}(-\psi)^i = -1 + \sqrt{5}, \quad \sum_{i=1}^{3}(\psi^3)^i = 49 - 22\sqrt{5}

Tapılmış qiymətləri yerinə yazaq:

\sum_{i=1}^{3} f_i^3 = \frac{(49 + 22\sqrt{5}) - 3(-1 - \sqrt{5}) + 3(-1 + \sqrt{5}) - (49 - 22\sqrt{5})}{5\sqrt{5}} = \frac{50\sqrt{5}}{5\sqrt{5}} = 10

Nəticə birbaşa hesablama ilə üst-üstə düşür:

f_1^3 + f_2^3 + f_3^3 = 1^3 + 1^3 + 2^3 = 1 + 1 + 8 = 10

\boldsymbol{k = 4} üçün nümunəyə baxaq (xüsusi hal). Burada

t_0 = \varphi^4, \quad t_1 = \varphi^3\psi = -\varphi^2, \quad t_2 = \varphi^2\psi^2 = 1, \quad t_3 = \varphi\psi^3 = -\psi^2, \quad t_4 = \psi^4

və

\sum_{i=1}^{n} f_i^4 = \frac{1}{25}\Biggl(\sum_{i=1}^{n}(\varphi^4)^i - 4\sum_{i=1}^{n}(-\varphi^2)^i + 6n - 4\sum_{i=1}^{n}(-\psi^2)^i + \sum_{i=1}^{n}(\psi^4)^i\Biggr)

Orta toplanan t_2 = 1 vuruğuna uyğundur: həndəsi silsilənin cəmi düsturu ona tətbiq olunmur, 1 + 1 + \ldots + 1 cəmi isə -ə bərabərdir. Proqramda məhz bu hal ayrıca emal olunur. Məsələn, n = 3 olduqda alırıq:

f_1^4 + f_2^4 + f_3^4 = 1^4 + 1^4 + 2^4 = 1 + 1 + 16 = 18

Alqoritmin reallaşdırılması

Modul üçün sabitini elan edək.

#define MOD 1000000007

Binomial əmsalların qiymətlərini massivində saxlayacağıq.

vector<long long> Cnk;

Z_{MOD} [\sqrt{5}] meydanında arifmetikanı reallaşdırmaq üçün strukturunu elan edək. Struktur x + y \sqrt{5} şəklində ədədi saxlayır.

struct Num
{
  long long x, y;
  Num(long long x = 0, long long y = 0) : x(x% MOD), y(y% MOD) {}
};

add funksiyası Z_{MOD} [\sqrt{5}] meydanında toplamanı reallaşdırır.

Num add(const Num& a, const Num& b)
{
  return Num((a.x + b.x) % MOD, (a.y + b.y) % MOD);
}

mult funksiyası Z_{MOD} [\sqrt{5}] meydanında vurmanı reallaşdırır.

Num mult(const Num& a, const Num& b)
{
  return Num(
    (a.x * b.x + 5 * a.y % MOD * b.y) % MOD,
    (a.x * b.y + a.y * b.x) % MOD
  );
}

pw funksiyası Z_{MOD} [\sqrt{5}] meydanında binar qüvvətə yüksəltməni reallaşdırır, burada qüvvət üstü tam ədəddir.

Num pw(Num base, long long exp)
{
  Num res(1, 0);
  while (exp)
  {
    if (exp & 1) res = mult(res, base);
    base = mult(base, base);
    exp >>= 1;
  }
  return res;
}

pw funksiyası modulu üzrə a^b qüvvətini sürətli binar qüvvətə yüksəltmə ilə hesablayır.

long long pw(long long a, long long b)
{
  long long res = 1;
  a %= MOD;
  while (b)
  {
    if (b & 1) res = (res * a) % MOD;
    a = a * a % MOD;
    b >>= 1;
  }
  return res;
}

inv funksiyası Z_{MOD} [\sqrt{5}] meydanında elementinin tərs elementini hesablayır.

Əgər

a = x + y \sqrt{5},

olarsa, onda onun tərs elementi belə olacaq:

a^{-1} = \frac{1}{x+y\sqrt{5}} = \frac{x-y\sqrt{5}}{x^2-5y^2}
Num inv(const Num& a)
{
  long long den = (a.x * a.x - 5 * a.y * a.y) % MOD;
  if (den < 0) den += MOD;

  long long invDen = pw(den, MOD - 2);

  return Num(
    a.x * invDen % MOD,
    (MOD - a.y) * invDen % MOD
  );
}

divide funksiyası Z_{MOD} [\sqrt{5}] meydanında bölməni reallaşdırır:

\frac{a}{b} = a \cdot b^{-1}
Num divide(const Num& a, const Num& b)
{
  return mult(a, inv(b));
}

Proqramın əsas hissəsi. Giriş verilənlərini oxuyuruq.

scanf("%lld %lld", &n, &k);

C_k^0, C_k^1, C_k^2, ..., C_k^k binomial əmsallarını hesablayırıq və onları massivinə yazırıq. Qeyd edək ki,

Cnk[i] = C_k^i = C_k^{i-1} \cdot \frac{k - i + 1}{i}
Cnk.resize(k + 1);
Cnk[0] = 1;
for (i = 1; i <= k; i++)
{
  Cnk[i] = Cnk[i - 1] * (k - i + 1) % MOD;
  Cnk[i] = Cnk[i] * pw(i, MOD - 2) % MOD;
}

inv2 = 2^{-1} \mod MOD = (MOD + 1) / 2 qiymətini hesablayırıq.

long long inv2 = (MOD + 1) / 2;

Sabitləri inisializasiya edirik: phi = \phi = \frac{1 + \sqrt{5}}{2} və psi = \psi = \frac{1 - \sqrt{5}}{2}.

Num phi(inv2, inv2);
Num psi(inv2, MOD - inv2);

ratio = \psi / \phi qiymətini hesablayırıq.

Num ratio = divide(psi, phi);

Z_{MOD} [\sqrt{5}] meydanında və sabitlərini inisializasiya edirik.

Num one(1, 0);
Num minus_one(MOD - 1, 0);

Cavabı dəyişənində toplayacağıq.

Num res(0, 0);

t = \phi^k qiymətini inisializasiya edirik. Sonra dövrdə bu qiyməti -ya vuraraq aşağıdakıları alacağıq:

\phi^k, \phi^{k-1}\psi, \phi^{k-2}\psi^2, ..., \phi\psi^{k-1}, \psi^k
Num t = pw(phi, k);

dəyişənində aşağıdakı cəmi hesablayırıq:

\sum_{i=1}^{n} f_i^k = \frac{1}{(\sqrt{5})^k} \sum_{j=0}^{k} (-1)^j C_k^j \sum_{i=1}^{n} \left(\phi^{k-j}\psi^j\right)^i

Axtarılan cəm k + 1 toplanandan ibarətdir. Buna görə k + 1 iterasiya yerinə yetiririk.

for (j = 0; j <= k; j++)
{
  Num term;

Bu anda t = \phi^{k-j} \psi^j. Həndəsi silsilənin cəmini hesablayırıq:

term = \sum_{i=1}^{n} t^i = \frac{t(t^n-1)}{t-1}

Lakin t = 1 halını ayrıca emal etmək lazımdır, çünki həndəsi silsilənin cəmi düsturunda -a bölmə olacaq. t = 1 olduqda cəm 1 + 1 + 1 + ... + 1 ( dəfə) şəklini alır və -ə bərabərdir.

  if (t.x == 1 && t.y == 0)
    term = Num(n % MOD, 0);
  else
  {
    Num tn = pw(t, n);
    Num num = add(tn, minus_one);     // t^n - 1
    term = mult(t, num);              // t * (t^n - 1)
    Num den = add(t, minus_one);      // t - 1
    term = divide(term, den);         // t * (t^n - 1) / (t - 1)
  }

term = (-1)^j C_k^j \cdot term qiymətini hesablayırıq.

  long long coef = Cnk[j];
  if (j & 1) coef = MOD - coef;

  term.x = term.x * coef % MOD;
  term.y = term.y * coef % MOD;

Növbəti toplananını nəticəsinə əlavə edirik.

  res = add(res, term);

-ni -ya vururuq və t = \phi^{k-j-1} \psi^{j + 1} alırıq.

  t = mult(t, ratio);
}

-i (\sqrt{5})^k-ya bölmək qalır.

Num sqrt5(0, 1);
Num sqrt5k = pw(sqrt5, k);
res = divide(res, sqrt5k);

Cavabı çap edirik.

printf("%lld\n", res.x);