【问题标题】:Calculate Huge Fibonacci number modulo M in C++在 C++ 中计算巨大的斐波那契数模 M
【发布时间】:2016-05-03 16:41:25
【问题描述】:

问题陈述:给定两个整数n和m,输出Fn mod m(即Fn除以m的余数)。

输入格式。输入由在同一行上给出的两个整数 n 和 m 组成(用空格分隔)。 约束。 1 ≤ n ≤ 10^18, 2 ≤ m ≤ 10^5

输出格式。输出 Fn mod m。

我尝试了以下程序,但没有成功。根据http://webspace.ship.edu/msrenault/fibonacci/fiblist.htm,方法 pi 返回正确的 Pisano 句点,但对于任何数字

#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';
}

确切的程序/逻辑在 python 中运行良好,正如预期的那样。这个 cpp 程序有什么问题?是数据类型吗?

【问题讨论】:

  • 是 10^18 还是 1018 ?在约束中?
  • 我尝试了以下程序,但它不起作用不是一个很好的描述。您需要告诉我们输入、输出和预期输出。还必须单步执行代码,看看哪里出了问题?
  • 在每一步之后计算余数,否则中间会溢出。
  • 当您使用它时,Fn 应该始终为正,所以我认为没有任何理由使用 signed long long 值。

标签: c++ algorithm fibonacci


【解决方案1】:

执行 10^18 加法 不会很实用。即使在 teraflop 计算机上,10^6 秒仍然是 277 小时。

但是 10^18 ~= 2^59.8 所以会有多达 60 个减半步骤。

一步计算 (a,b) --&gt; (a^2 + b^2, 2ab + b^2) 以从 (n-1,n)th 到 (2n-1,2n)th 连续斐波那契数对。

在每一步执行每个操作的模数计算。您需要容纳最大为 3*1010 &leq; 的整数。 235 幅度(即最多 35 位)。

(参见related older answer of mine)。

【讨论】:

  • 这是正确的方法。请注意,您需要将数字重复取一半,在需要的地方减去 1,以计算出另一个方向的序列。然后,您使用上面的方法进行备份以加倍,并使用 (a, b) -&gt; (b, a+b) 进行 +1 步骤。
【解决方案2】:

这是我解决这个问题的方法,效果很好,提交测试成功了……

我使用了一种更简单的方法来获得 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';
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-27
    • 1970-01-01
    • 2017-01-29
    • 2012-12-03
    • 2013-03-31
    • 1970-01-01
    • 2020-01-18
    • 1970-01-01
    相关资源
    最近更新 更多