Problem B: How many Fibs?
Recall the definition of the Fibonacci numbers:
f 1 := 1Given two numbers a and b, calculate how many Fibonacci numbers are in the range [ a, b].
f 2 := 2
f n := f n-1 + f n-2 (n>=3)
Input Specification
The input contains several test cases. Each test case consists of two non-negative integer numbers a and b. Input is terminated bya=b=0. Otherwise, a<=b<=10100. The numbers a and b are given with no superfluous leading zeros.
Output Specification
For each test case output on a single line the number of Fibonacci numbers fi with a<=fi<=b.
Sample Input
10 100 1234567890 9876543210 0 0
Sample Output
5 4
一开始用 double 代 fabonacci 公式: 1 / 根5 * (((1 + 根5) / 2) ^ n - ((1 + 根5) / 2) ^ n),用二分法求起止项号,并用项号相减,WA,原因是 double 精度不够。
后来发现第400多项就可以达到 10 的 100 次方,只要预先计算这 400 多项,然后每读入一组数据暴力枚举即可,不需要二分法如此复杂,不过需要写一下高精度加法。
WA代码
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cmath>
#include <algorithm>
const double esp = 1e-5;
double fib (double i) {
static double sqrt5 = sqrt (5.0);
return 1.0 / sqrt5 * (pow ((1.0 + sqrt5) / 2, i) - pow ((1.0 - sqrt5) / 2, i));
}
long long bin (double f) {
long long hi = 1;
while (fib (hi) < f) {
hi *= 2;
}
if (hi < 2) {
return hi;
}
long long lo = hi / 2;
double fib_lo = fib (lo);
double fib_hi = fib (hi);
double t = (fib_lo - f) * (fib_hi - f);
while (lo < hi && (t < 0 || fabs (t) < esp)) {
long long mid = (lo + hi) >> 1;
double fib_mid = fib (mid);
t = (fib_lo - f) * (fib_mid - f);
if (t < 0.0 || fabs (t) < esp) {
hi = mid;
fib_hi = fib_mid;
} else {
lo = mid + 1;
fib_lo = fib (mid + 1);
t = (fib_lo - f) * (fib_hi - f);
}
}
return lo;
}
int main () {
double a, b;
while (scanf ("%lf%lf", &a, &b) == 2 && (fabs (a) > esp || fabs (b) > esp)) {
long long ia = bin (a);
long long ib = bin (b);
ia = std::max (2LL, ia);
ib = std::max (2LL, ib);
#ifdef _DEBUG
printf ("ia = %lld, ib = %lld\n", ia, ib);
#endif
if (fabs (fib (ib) - b) < esp) {
printf ("%lld\n", ib - ia + 1);
} else {
printf ("%lld\n", ib - ia);
}
}
return 0;
}
AC代码
#include <cstdio>
#include <cassert>
#include <cstdlib>
#include <cstring>
#define FIBS_MAX 500
#define DIGS_MAX 110
int fib [FIBS_MAX][DIGS_MAX];
void Add (int *a, int *b) {
int car = 0;
for (int i=0; i<DIGS_MAX; ++i) {
int t = a[i] + b[i] + car;
car = t / 10;
a[i] = t % 10;
}
assert (car == 0);
}
void InitFibs () {
memset (fib, 0, sizeof (fib));
fib[1][0] = 1;
fib[2][0] = 2;
for (int i=3; i<FIBS_MAX; ++i) {
Add (fib[i], fib[i - 1]);
Add (fib[i], fib[i - 2]);
}
}
bool IsLess (int *a, int *b) {
for (int i=DIGS_MAX-1; i>=0; --i) {
if (a[i] < b[i]) {
return true;
} else if (a[i] > b[i]) {
return false;
}
}
return false;
}
void GetInt (int *a) {
static char s[1024];
if (scanf ("%s", s) == EOF) {
exit (0);
}
char *p = s + strlen (s);
memset (a, 0, sizeof (*a) * DIGS_MAX);
do {
*a++ = *--p - '0';
} while (p > s);
}
bool IsZero (int *a) {
for (int i=0; i<DIGS_MAX; ++i) {
if (a[i]) {
return false;
}
}
return true;
}
void Solve () {
int a[DIGS_MAX];
int b[DIGS_MAX];
GetInt (a);
GetInt (b);
if (IsZero (a) && IsZero (b)) {
exit (0);
}
int i = 0;
while (++i < FIBS_MAX && IsLess (fib[i], a)) {}
int k = 0;
while (++k < FIBS_MAX && IsLess (fib[k], b)) {}
assert (i < FIBS_MAX && k < FIBS_MAX && k >= i);
if (! IsLess (b, fib[k])) {
printf ("%d\n", k - i + 1);
} else {
printf ("%d\n", k - i);
}
}
int main () {
InitFibs ();
while (true) {
Solve ();
}
return 0;
}