首页 > 其他分享 >斐波那契前 n 项和

斐波那契前 n 项和

时间:2023-01-28 17:11:06浏览次数:50  
标签:tmp begin end int times 斐波 bmatrix 契前

斐波那契前 n 项和

大家都知道 Fibonacci 数列吧,$f_1=1,f_2=1,f_3=2,f_4=3, \ldots ,f_n=f_{n−1}+f_{n−2}$。

现在问题很简单,输入 $n$ 和 $m$,求 $f_n$ 的前 $n$ 项和 $S_n \bmod m$。

输入格式

共一行,包含两个整数 $n$ 和 $m$。

输出格式

输出前 $n$ 项和 $S_n \bmod m$ 的值。

数据范围

$1 \leq n \leq 2000000000$,
$1 \leq m \leq 1000000010$

输入样例:

5 1000

输出样例:

12

 

解题思路

  遇到递推的题目想想能不能构造出矩阵,然后通过矩阵乘法和快速幂来快速求出第$n$项是什么。

  设斐波那契的第$n$项为$f_n$,定义向量$F_n = \begin{bmatrix} f_n & f_{n+1} \end{bmatrix}$,那么$F_{n+1} = \begin{bmatrix} f_{n+1} & f_{n+2} \end{bmatrix}$。尝试构造一个$2 \times 2$的矩阵$A$使得$F_n \times A = F_{n+1}$。容易发现$$\begin{bmatrix} f_n & f_{n+1} \end{bmatrix} \times \begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix} = \begin{bmatrix} f_{n+1} & f_{n+2} \end{bmatrix}$$

  因此$A = \begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}$。同时根据矩阵乘法的结合律,有$F_n = F_1 \times A^{n-1}$,$A^{n-1}$可以用快速幂来算。

  现在的问题是求斐波那契的前$n$项和$S_n = \sum\limits_{i=1}^{n}{f_n}$。那么我们构造向量$F_n = \begin{bmatrix} f_n & f_{n+1} & S_n \end{bmatrix}$,继续找到一个$3 \times 3$的矩阵$A$使得$F_n \times A = F_{n+1}$。同样有$$\begin{bmatrix} f_n & f_{n+1} & S_n \end{bmatrix} \times \begin{bmatrix} 0 & 1 & 0 \\ 1 & 1 & 1 \\ 0 & 0 & 1 \end{bmatrix} = \begin{bmatrix} f_{n+1} & f_{n+2} & S_{n+1} \end{bmatrix}$$

  那么$A = \begin{bmatrix} 0 & 1 & 0 \\ 1 & 1 & 1 \\ 0 & 0 & 1 \end{bmatrix}$。$F_n = F_1 \times A^{n-1}$,其中$F_1 = \begin{bmatrix} 1 & 1 & 1 \end{bmatrix}$。

  AC代码如下,时间复杂度为$O\left( 3^3 \times \log{n} \right)$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n, m;
 5 int a[3][3] = {
 6     {0, 1, 0},
 7     {1, 1, 1},
 8     {0, 0, 1}
 9 };
10 
11 void mul(int c[], int a[], int b[][3]) {    // c = a * b
12     int tmp[3] = {0};
13     for (int i = 0; i < 3; i++) {
14         for (int j = 0; j < 3; j++) {
15             tmp[i] = (tmp[i] + 1ll * a[j] * b[j][i]) % m;
16         }
17     }
18     memcpy(c, tmp, sizeof(tmp));
19 }
20 
21 void mul(int c[][3], int a[][3], int b[][3]) {  // c = a * b
22     int tmp[3][3] = {0};
23     for (int i = 0; i < 3; i++) {
24         for (int j = 0; j < 3; j++) {
25             for (int k = 0; k < 3; k++) {
26                 tmp[i][j] = (tmp[i][j] + 1ll * a[i][k] * b[k][j]) % m;
27             }
28         }
29     }
30     memcpy(c, tmp, sizeof(tmp));
31 }
32 
33 int main() {
34     cin >> n >> m;
35     int f1[3] = {1, 1, 1};
36     n--;
37     while (n) {
38         if (n & 1) mul(f1, f1, a);  // f1 = f1 * a
39         mul(a, a, a);   // a = a * a
40         n >>= 1;
41     }
42     cout << f1[2];
43     
44     return 0;
45 }

  为了方便统一成两个矩阵的乘法,可以把$F_1$扩展为$3 \times 3$的矩阵$F1 = \begin{bmatrix} 1 & 1 & 1 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \end{bmatrix}$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int n, m;
 5 int a[3][3] = {
 6     {0, 1, 0},
 7     {1, 1, 1},
 8     {0, 0, 1}
 9 };
10 
11 void mul(int c[][3], int a[][3], int b[][3]) {
12     int tmp[3][3] = {0};
13     for (int i = 0; i < 3; i++) {
14         for (int j = 0; j < 3; j++) {
15             for (int k = 0; k < 3; k++) {
16                 tmp[i][j] = (tmp[i][j] + 1ll * a[i][k] * b[k][j]) % m;
17             }
18         }
19     }
20     memcpy(c, tmp, sizeof(tmp));
21 }
22 
23 int main() {
24     cin >> n >> m;
25     int f1[3][3] = {1, 1, 1};
26     n--;
27     while (n) {
28         if (n & 1) mul(f1, f1, a);
29         mul(a, a, a);
30         n >>= 1;
31     }
32     cout << f1[0][2];
33     
34     return 0;
35 }

 

参考资料

  AcWing 1303. 斐波那契前 n 项和(算法提高课):https://www.acwing.com/video/704/

标签:tmp,begin,end,int,times,斐波,bmatrix,契前
From: https://www.cnblogs.com/onlyblues/p/17070871.html

相关文章

  • 【闲话】1.27 斐波那契数列一个性质及推广
    众所周知众所周知,斐波那契数列有一个性质:\[\gcd(f_{n},f_{m})=f_{\gcd(n,m)}\]在证明他之前,先来看个引理:\(\text{Lemma}\1\)\[f_{n+m}=f_{n}\timesf_{m-1}+f_{n+1......
  • 迭代:求第n个斐波那契数(不考虑溢出)
    斐波那契数列:前两个数之和等于第三个数(如11235813213455......)描述第n个斐波那契数列:由图Fibn<=21n>2Fib(n-1)+Fib(n-2)可知#include<stdio.h>intFib(intn){i......
  • 斐波那契数列的多种实现和性能
    目录0.普通斐波那契1.结果缓存2.自动化结果缓存3.迭代4.生成器0.普通斐波那契importtimestart=time.time()deffib0(n:int)->int:ifn<2:......
  • SQL Server 斐波那契数列
    斐波那契数列,又称黄金分割数列,指的是这样一个数列:0、1、1、2、3、5、8、13、21、……在数学上,斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)在现......
  • 斐波那契数
    一、背景与定义      有这样一个数列1,1,2,3,5,8,13,21,34,55,89,144,……这个数列前两个数均为1,从第3项开始,每一项都等于前两项之和。        数列最早被提出是,......
  • 509. 斐波那契数列
    问题描述https://leetcode.cn/problems/fibonacci-number/description/解题思路最经典的递归问题,它的问题描述就是递归的。先考虑参数和返回值。参数就是n,返回值是fib(......
  • 求第n个斐波那契数。(用递归和循环的方法对比)
    写这个代码的过程中出现的问题及改进方法:用递归实现#include<stdio.h>intFib(intn){if(n<=2)return1;elsereturnFib(n-1)+Fib(n-2);}......
  • 1、尾递归及优化 ,例:斐波那契数列 2、递归转循环,蹦床函数
    1、函数调用自身,即为递归,在return时调用自身,即为尾递归;递归非常消耗内存,其原因是需要同时保存成成百上千的调用帧,这容易发生栈溢出错误;但是尾递归只存在一个调用帧,所以永......
  • 斐波那契公约数证明
    斐波那契公约数证明已知\(F_n\)为斐波那契数列,求证:\(∀n,m∈Z^+,(F_n,\F_m)=F_{(n,\m)}\)证明:令\(n<m\),\(F_n=F_1*a,\F_{n+1}=F_2*b\)\(F_{......
  • 【编程实践】手把手带你利用Python简单实现斐波那契数列
    前言什么是斐波那契数列?斐波那契数列的提出者,是意大利数学家列昂纳多·斐波那契(LeonardoFibonacci),生于公元1170年,卒于1250年,籍贯是比萨。他被人称作“比萨的列昂纳多”。当......