问题描述
我正在解决一个 CSES 问题,在该问题中我必须找到前“n”个斐波那契数的总和。代码:
#pragma GCC optimize("Ofast")
#include <iostream>
using namespace std;
int main()
{
unsigned long long int n;
scanf("%llu",&n);
unsigned long long int seq[n];
seq[0] = 0;
seq[1] = 1;
unsigned long long int mod = 1000000000 + 7;
for (unsigned long long int i = 2; i < n + 1; i++) {
seq[i] = (seq[i - 1] + seq[i - 2]) % mod;
}
cout << seq[n];
}
问题指定 n 的值可以达到 10^18,因此我使用 unsigned long long int
来初始化 n。该问题还指示给出模 7 的答案。该代码适用于最多 4 位数的 n 值,但在 n 值上升到 10^18 的上限时中断。它给出了 (0xC00000FD)
错误并且不返回任何内容。请帮助我理解这里的问题以及如何处理它。任何其他建议也将不胜感激。
解决方法
在进行模块化添加时,您需要将 mod 应用于您添加的每个值。
例如,(a + b) % c = (a % c + b % c) % c。
这意味着在您的代码中:
seq[i] = (seq[i - 1] % mod + seq[i - 2] % mod) % mod;
否则,seq[i - 1]
和 seq[i - 2]
的相加会导致溢出。
阅读有关模算术 here 的更多信息。
,在这个问题中
F[i] -> 第 i 个斐波那契数。 MOD = 1e9 + 7. n
F[n] % MOD = ?
F[n] = F[n-1] + F[n-2] 如果你用循环计算这个,你会得到 TL
这样你就可以优化这个解决方案
现在你用递归计算 F[n]
F[2*n] = - F[n] * F[n] + 2 * F[n] * F[n+1]
F[2*n+1] = F[n] * F[n] + F[n+1] * F[n+1]
这是我的解决方案
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll MOD = 1e9+7;
void fib(ll n,ll &a,ll &b){
if(n == 0){
a = 0;
b = 1;
return;
}
ll x,y;
if(n%2==1){
fib(n-1,x,y);
a = y;
b = (x+y)%MOD;
return;
}
fib(n/2,y);
a = (x*(2*y +MOD -x)%MOD)%MOD;
b = ((x*x)%MOD+(y*y)%MOD)%MOD;
return;
}
int main(){
ll N,a,b;
cin >> N;
fib(N,b);
cout << a;
}
,
我认为这段代码的问题在于您正在创建一个大小为 seq[n]
的数组 n
,这可能导致 Linux 上的 SEGFAULT
和 Windows 上的 STATUS_STACK_OVERFLOW (0xc00000fd)
对于大数,这是指堆栈耗尽。
下面我给出了你算法的改进版本,它使用固定的内存大小,对于模加,我使用sum_by_modulo
函数,以避免(a + b) % m
运算中的溢出,其原理被描述为 here。
#pragma GCC optimize("Ofast")
#include <iostream>
typedef unsigned long long int ullong;
ullong sum_by_modulo(ullong a,ullong b,ullong m){
ullong sum;
a %= m;
b %= m;
ullong c = m - a;
if (b==c)
sum = 0;
if (b<c)
sum = a + b;
if (b > c)
sum = b-c;
return sum;
}
int main()
{
ullong n;
ullong t1 = 0,t2 = 1,nextTerm = 0;
ullong modulo = 1000000000 + 7;
std::cout << "Enter the number of term: ";
std::cin >> n;
for (ullong i = 1; i <= n; ++i)
{
if(i == 1)
continue;
if(i == 2)
continue;
nextTerm = sum_by_modulo(t1,t2,modulo);
t1 = t2;
t2 = nextTerm;
}
std::cout << nextTerm << " ";
return 0;
}