1303 斐波那契前 n 项和(矩阵乘法)

1. 问题描述:

大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f4=3,…,fn=fn−1+fn−2。现在问题很简单,输入 n 和 m,求 fn 的前 n 项和 Snmodm。

输入格式

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

输出格式

输出前 n 项和 Snmodm 的值。

数据范围

1 ≤ n ≤ 2000000000,
1 ≤ m ≤ 1000000010

输入样例:
5 1000
输出样例:
12
来源:https://www.acwing.com/problem/content/description/1305/

2. 思路分析:

这道题目矩阵乘法的经典应用,矩阵乘法经常与快速幂结合在一起,难点在于将矩阵的前n项构造出来,因为这道题目需要求解的是前n项的和,所以可以将前n项和s放入到矩阵中,这样可以在矩阵乘法中计算出s,令Fn = [fn,fn+1,Sn],Fn+1 = [fn+1,fn+2,Sn+1],可以构造出对应的矩阵A,可以根据下面的式子计算矩阵乘法即可:

1303 斐波那契前 n 项和(矩阵乘法)_第1张图片

3. 代码如下:

from typing import List


class Solution:
    # 矩阵乘法满足结合律所以可以使用快速幂来解决
    # res = res * a
    def mul(self, n: int, mod: int, a: List[int], b: List[List[int]]):
        temp = [0] * n
        for i in range(n):
            for j in range(n):
                temp[i] = (temp[i] + a[j] * b[j][i]) % mod
        # 将结果复制到原来的a中, a其实是f1
        for i in range(n):
            a[i] = temp[i]

    # a = a * a
    def mul2(self, n: int, mod: int, a: List[List[int]], b: List[List[int]]):
        temp = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
        for i in range(n):
            for j in range(n):
                for k in range(n):
                    temp[i][j] = (temp[i][j] + a[i][k] * b[k][j]) % mod
        for i in range(n):
            for j in range(n):
                a[i][j] = temp[i][j]

    def process(self):
        n, m = map(int, input().split())
        # 将前n项和存储到矩阵中, f1的第三个元素存储的是前n项的和
        f1 = [1, 1, 1]
        a = [[0, 1, 0], [1, 1, 1], [0, 0, 1]]
        # 因为是从A1开始的所以计算的其实是A ^ (n - 1)
        n -= 1
        while n > 0:
            # res = res * a
            if n & 1:
                self.mul(3, m, f1, a)
            self.mul2(3, m, a, a)
            n >>= 1
        return f1[2]


if __name__ == '__main__':
    print(Solution().process())

你可能感兴趣的:(acwing-提高,算法)