在 C++ 中计算巨大的斐波那契数模 M
Calculate Huge Fibonacci number modulo M in C++
问题陈述:给定两个整数n和m,输出Fnmodm(即Fn除以m的余数)。
输入格式。输入由在同一行给出的两个整数 n 和 m 组成(由 space 分隔)。
约束。 1 ≤ n ≤ 10^18, 2 ≤ m ≤ 10^5
输出格式。输出 Fn mod m.
我尝试了以下程序,但没有用。尽管根据 http://webspace.ship.edu/msrenault/fibonacci/fiblist.htm
对于任何数字,方法 pi 都会返回正确的皮萨诺周期
#include <iostream>
long long pi(long long m) {
long long result = 2;
for (long long fn2 = 1, fn1 = 2 % m, fn = 3 % m;
fn1 != 1 || fn != 1;
fn2 = fn1, fn1 = fn, fn = (fn1 + fn2) % m
) {
result++;
}
return result;
}
long long get_fibonaccihuge(long long n, long long m) {
long long periodlength = pi(m);
int patternRemainder = n % periodlength;
long long *sum = new long long[patternRemainder];
sum[0] = 0;
sum[1] = 1;
for (int i = 2; i <= patternRemainder; ++i)
{
sum[i] = sum[i - 1] + sum[i - 2];
}
return sum[patternRemainder] % m;
}
int main() {
long long n, m;
std::cin >> n >> m;
std::cout << get_fibonaccihuge(n, m) << '\n';
}
确切的 program/logic 在 python 中运行良好,符合预期。这个 cpp 程序有什么问题?是数据类型吗?
执行 10^18 加法 不会很实用。即使在 teraflop 计算机上,10^6 秒仍然是 277 小时。
但是 10^18 ~= 2^59.8 所以将有多达 60 个减半步骤。
一步计算 (a,b) --> (a^2 + b^2, 2ab + b^2)
从第 (n-1,n)
到第 (2n-1,2n)
个连续的斐波那契数对。
在每个步骤中对每个操作执行模数计算。您需要容纳最多 3*1010 ≤ 的整数。 235 大小(即最多 35 位)。
(比照related older answer of mine)。
这是我针对这个问题的解决方案,效果很好,提交测试成功...
我使用了一种更简单的方法来获取 pisoano 周期(pisano 周期是这个问题中的主要棘手部分)...我希望能有所帮助
#include <iostream>
using namespace std;
unsigned long long get_fibonacci_huge_naive(unsigned long long n, unsigned long long m)
{
if (n <= 1)
return n;
unsigned long long previous = 0;
unsigned long long current = 1;
for (unsigned long long i = 0; i < n - 1; ++i)
{
unsigned long long tmp_previous = previous;
previous = current;
current = tmp_previous + current;
}
return current % m;
}
long long get_pisano_period(long long m)
{
long long a = 0, b = 1, c = a + b;
for (int i = 0; i < m * m; i++)
{
c = (a + b) % m;
a = b;
b = c;
if (a == 0 && b == 1)
{
return i + 1;
}
}
}
unsigned long long get_fibonacci_huge_faster(unsigned long long n, unsigned long long m)
{
n = n % get_pisano_period(m);
unsigned long long F[n + 1] = {};
F[0] = 0;
F[-1] = 1;
for (int i = 1; i <= n; i++)
{
F[i] = F[i - 1] + F[i - 2];
F[i] = F[i] % m;
}
return F[n];
}
int main()
{
unsigned long long n, m;
std::cin >> n >> m;
std::cout << get_fibonacci_huge_faster(n, m) << '\n';
}
问题陈述:给定两个整数n和m,输出Fnmodm(即Fn除以m的余数)。
输入格式。输入由在同一行给出的两个整数 n 和 m 组成(由 space 分隔)。 约束。 1 ≤ n ≤ 10^18, 2 ≤ m ≤ 10^5
输出格式。输出 Fn mod m.
我尝试了以下程序,但没有用。尽管根据 http://webspace.ship.edu/msrenault/fibonacci/fiblist.htm
对于任何数字,方法 pi 都会返回正确的皮萨诺周期#include <iostream>
long long pi(long long m) {
long long result = 2;
for (long long fn2 = 1, fn1 = 2 % m, fn = 3 % m;
fn1 != 1 || fn != 1;
fn2 = fn1, fn1 = fn, fn = (fn1 + fn2) % m
) {
result++;
}
return result;
}
long long get_fibonaccihuge(long long n, long long m) {
long long periodlength = pi(m);
int patternRemainder = n % periodlength;
long long *sum = new long long[patternRemainder];
sum[0] = 0;
sum[1] = 1;
for (int i = 2; i <= patternRemainder; ++i)
{
sum[i] = sum[i - 1] + sum[i - 2];
}
return sum[patternRemainder] % m;
}
int main() {
long long n, m;
std::cin >> n >> m;
std::cout << get_fibonaccihuge(n, m) << '\n';
}
确切的 program/logic 在 python 中运行良好,符合预期。这个 cpp 程序有什么问题?是数据类型吗?
执行 10^18 加法 不会很实用。即使在 teraflop 计算机上,10^6 秒仍然是 277 小时。
但是 10^18 ~= 2^59.8 所以将有多达 60 个减半步骤。
一步计算 (a,b) --> (a^2 + b^2, 2ab + b^2)
从第 (n-1,n)
到第 (2n-1,2n)
个连续的斐波那契数对。
在每个步骤中对每个操作执行模数计算。您需要容纳最多 3*1010 ≤ 的整数。 235 大小(即最多 35 位)。
(比照related older answer of mine)。
这是我针对这个问题的解决方案,效果很好,提交测试成功...
我使用了一种更简单的方法来获取 pisoano 周期(pisano 周期是这个问题中的主要棘手部分)...我希望能有所帮助
#include <iostream>
using namespace std;
unsigned long long get_fibonacci_huge_naive(unsigned long long n, unsigned long long m)
{
if (n <= 1)
return n;
unsigned long long previous = 0;
unsigned long long current = 1;
for (unsigned long long i = 0; i < n - 1; ++i)
{
unsigned long long tmp_previous = previous;
previous = current;
current = tmp_previous + current;
}
return current % m;
}
long long get_pisano_period(long long m)
{
long long a = 0, b = 1, c = a + b;
for (int i = 0; i < m * m; i++)
{
c = (a + b) % m;
a = b;
b = c;
if (a == 0 && b == 1)
{
return i + 1;
}
}
}
unsigned long long get_fibonacci_huge_faster(unsigned long long n, unsigned long long m)
{
n = n % get_pisano_period(m);
unsigned long long F[n + 1] = {};
F[0] = 0;
F[-1] = 1;
for (int i = 1; i <= n; i++)
{
F[i] = F[i - 1] + F[i - 2];
F[i] = F[i] % m;
}
return F[n];
}
int main()
{
unsigned long long n, m;
std::cin >> n >> m;
std::cout << get_fibonacci_huge_faster(n, m) << '\n';
}