给定两个表示范围[M,N]的非负整数M,N ,其中M≤N,任务是找到F M + F M + 1 …+ F N之和的最后一位,其中F K为斐波那契数列中的第K个斐波那契数。
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, …
例子:
Input: M = 3, N = 9
Output: 6
Explanation:
We need to find F3 + F4 + F5 + F6 + F7 + F8 + F9
=> 2 + 3 + 5 + 8 + 13 + 21 + 34 = 86.
Clearly, the last digit of the sum is 6.
Input: M = 3, N = 7
Output: 1
Explanation:
We need to find F3 + F4 + F5 + F6 + F7
=> 2 + 3 + 5 + 8 + 13 = 31.
Clearly, the last digit of the sum is 1.
朴素方法:针对此问题的朴素方法是一个一个地找出所有第K个斐波那契数的和,其中K处于[M,N]范围内,并最后返回总和的最后一位。此方法的时间复杂度为O(N),并且该方法对于N的高阶值失败。
高效方法:针对此问题的有效方法是使用皮萨诺时期的概念。
- 这个想法是分别计算(M – 1)和N个斐波那契数之和,然后减去计算值的最后一位。
- 这是因为所有K个第Fibonacci数之和的最后一位数字,使得K处于[M,N]范围内,等于该范围内所有K个Fibonacci数之和的最后一位数字之差。 [0,N]以及所有第K个斐波纳契数的总和,范围为[0,M – 1] 。
- 这些值可以分别在很短的时间内通过皮萨诺时期的概念来计算。
- 让我们了解皮萨诺时期的运作方式。下表说明了前10个斐波纳契数以及在对这些数执行模2运算时获得的值。
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
Fi | 0 | 1 | 1 | 2 | 3 | 5 | 8 | 13 | 21 | 34 | 55 |
Fi mod 2 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 10 |
- 显然,皮萨诺周期(F为i mod 2)为3,因为011重复本身和长度(011)= 3。
- 现在,让我们观察以下身份:
7 = 2 * 3 + 1
Dividend = (Quotient × Divisor) + Remainder
=> F7 mod 2 = F1 mod 2 = 1.
- 因此,在给定F i mod 10的Pisano周期为60的情况下,我们只计算总和直到剩下的余数,而不是计算范围[0,N]中所有数字的总和的最后一位。
下面是上述方法的实现:
C++
// C++ program to calculate
// last digit of the sum of the
// fibonacci numbers from M to N
#include
using namespace std;
// Calculate the sum of the first
// N Fibonacci numbers using Pisano
// period
long long fib(long long n)
{
// The first two Fibonacci numbers
long long f0 = 0;
long long f1 = 1;
// Base case
if (n == 0)
return 0;
if (n == 1)
return 1;
else
{
// Pisano period for % 10 is 60
long long rem = n % 60;
// Checking the remainder
if(rem == 0)
return 0;
// The loop will range from 2 to
// two terms after the remainder
for(long long i = 2; i < rem + 3; i++)
{
long long f = (f0 + f1) % 60;
f0 = f1;
f1 = f;
}
long long s = f1 - 1;
return s;
}
}
// Driver Code
int main()
{
long long m = 10087887;
long long n = 2983097899;
long long final = abs(fib(n) - fib(m - 1));
cout << final % 10 << endl;
}
// This code is contributed by Bhupendra_Singh
Java
// Java program to calculate
// last digit of the sum of the
// fibonacci numbers from M to N
import java.util.*;
class GFG{
// Calculate the sum of the first
// N Fibonacci numbers using Pisano
// period
static int fib(long n)
{
// The first two Fibonacci numbers
int f0 = 0;
int f1 = 1;
// Base case
if (n == 0)
return 0;
if (n == 1)
return 1;
else
{
// Pisano period for % 10 is 60
int rem = (int) (n % 60);
// Checking the remainder
if(rem == 0)
return 0;
// The loop will range from 2 to
// two terms after the remainder
for(int i = 2; i < rem + 3; i++)
{
int f = (f0 + f1) % 60;
f0 = f1;
f1 = f;
}
int s = f1 - 1;
return s;
}
}
// Driver Code
public static void main(String args[])
{
int m = 10087887;
long n = 2983097899L;
int Final = (int)Math.abs(fib(n) -
fib(m - 1));
System.out.println(Final % 10);
}
}
// This code is contributed by AbhiThakur
Python3
# Python3 program to calculate
# Last Digit of the sum of the
# Fibonacci numbers from M to N
# Calculate the sum of the first
# N Fibonacci numbers using Pisano
# period
def fib(n):
# The first two Fibonacci numbers
f0 = 0
f1 = 1
# Base case
if (n == 0):
return 0
if (n == 1):
return 1
else:
# Pisano Period for % 10 is 60
rem = n % 60
# Checking the remainder
if(rem == 0):
return 0
# The loop will range from 2 to
# two terms after the remainder
for i in range(2, rem + 3):
f =(f0 + f1)% 60
f0 = f1
f1 = f
s = f1-1
return(s)
# Driver code
if __name__ == '__main__':
m = 10087887
n = 2983097899
final = fib(n)-fib(m-1)
print(final % 10)
C#
// C# program to calculate
// last digit of the sum of the
// fibonacci numbers from M to N
using System;
class GFG{
// Calculate the sum of the first
// N fibonacci numbers using Pisano
// period
static int fib(long n)
{
// The first two fibonacci numbers
int f0 = 0;
int f1 = 1;
// Base case
if (n == 0)
return 0;
if (n == 1)
return 1;
else
{
// Pisano period for % 10 is 60
int rem = (int)(n % 60);
// Checking the remainder
if(rem == 0)
return 0;
// The loop will range from 2 to
// two terms after the remainder
for(int i = 2; i < rem + 3; i++)
{
int f = (f0 + f1) % 60;
f0 = f1;
f1 = f;
}
int s = f1 - 1;
return s;
}
}
// Driver Code
public static void Main()
{
int m = 10087887;
long n = 2983097899L;
int Final = (int)Math.Abs(fib(n) -
fib(m - 1));
Console.WriteLine(Final % 10);
}
}
// This code is contributed by Code_Mech
Javascript
5
时间复杂度: O(1) ,因为此代码对于任何输入数字都将运行近60次。