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,可以根据下面的式子计算矩阵乘法即可:
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())