ə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:
burada
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:
İşarə edək:
üzrə -dən -ə qədər cəmləyək və cəmləmə sırasını dəyişək:
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:
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^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:
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} şə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:
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:
p = 10^9 + 7 — tək sadə ədəddir, buna görə p + 1 cütdür və (p + 1) / 2 — tam ədəddir. O, -dən kiçikdir, yəni modulu üzrə adi qalıqdır.
Onu -yə vuraq: 2 \cdot (p + 1) / 2 = p + 1 \equiv 1 \pmod{p}.
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:
\varphi^2 = \varphi + 1 münasibətindən istifadə edərək -nin qüvvətlərini hesablayaq:
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,
bu da cavabla üst-üstə düşür: 1 + 1 + 2 + 3 = 7.
Nümunəyə baxaq: \boldsymbol{k = 3}. Fərqin kubunu açaq:
Silsilələrin vuruqları (\varphi\psi = -1 bərabərliyindən istifadə edirik):
Onda
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:
Onda
üçün cəmlər \sqrt{5}-in -\sqrt{5} ilə əvəz edilməsindən alınır:
Tapılmış qiymətləri yerinə yazaq:
Nəticə birbaşa hesablama ilə üst-üstə düşür:
\boldsymbol{k = 4} üçün nümunəyə baxaq (xüsusi hal). Burada
və
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:
Alqoritmin reallaşdırılması
Modul üçün sabitini elan edək.
#define MOD 1000000007Binomial ə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
olarsa, onda onun tərs elementi belə olacaq:
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:
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.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:
Num t = pw(phi, k);dəyişənində aşağıdakı cəmi hesablayırıq:
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:
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);