描述
提解
这道题,解法十分巧妙,思路不是自己想起来的,对斐波那契数列的性质不够了解,在相关讨论中找到一个ID为@wc
的大牛的思路,然后实现了一下,大牛思路如下:
斐波那契数列定义为 f[0]=f[1]=1, f[i]=f[i-1]+f[i-2] (i>=2) 只需打表前90项
从f[i]开始的连续f[i-1]项 的最短表示F[t] 是有规律的。
其前f[i-2]项和 从f[i-1]开始的连续f[i-2]项相等,其后f[i-3]项为 从f[i-2]开始的连续> f[i-3]项 每项+1比如,当i=6时,13开始的连续8项,即F[13],F[14],F[15]……F[20]为
1,2,2,2,3,2,3,3
前5项 正好和F[8],F[9],F[10],F[11],F[12]一样
后3项为F[5]+1,F[6]+1,F[7]+1;根据这个规律定义A[i]为 从f[i]开始的连续f[i-1]项 的最短表示F[t] 的和,也就是 A[i]=G[f[i+1] -1]-G[f[i]-1]
易知,A[1]=A[2]=1,A[i]=A[i-1]+A[i-2]+f[i-3]然后就是XJB搞了
(大牛们说话比较粗犷,习惯就好了)
这个思路把前半段解题思路给的十分详细,但是最后直接省略了,最后的这个可能不够整段的序列,着实难住我了,经过观察数列,发现这又和斐波那契数列的性质相关,具体是什么不好形容,看代码吧,我用while
循环实现的。
另外附一篇代码,是相同思路的另外一种表现形式,定义的数组有些不同而已。
代码
One:
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 90;
long long Fib[MAXN] = {1, 1};
long long A[MAXN] = {0, 1, 1};
void init()
{
for (int i = 2; i < MAXN; i++)
{
Fib[i] = Fib[i - 1] + Fib[i - 2];
}
for (int i = 3; i < MAXN; i++)
{
A[i] = A[i - 1] + A[i - 2] + Fib[i - 3];
}
return ;
}
int main(int argc, const char * argv[])
{
init();
int T;
cin >> T;
long long n;
while (T--)
{
long long ans = 0;
scanf("%lld", &n);
for (int i = 1; i < MAXN; i++)
{
if (Fib[i] + Fib[i - 1] - 1 <= n)
{
ans += A[i];
}
else
{
long long sur = n - Fib[i] + 1;
while (sur)
{
for (i--; i >= 1; i--)
{
if (Fib[i - 1] <= sur)
{
sur -= Fib[i - 1];
ans += A[i] + sur;
break;
}
}
}
break;
}
}
printf("%lld\n", ans);
}
return 0;
}
Two:
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 90;
ll f[MAXN], g[MAXN];
ll F(ll n)
{
int x;
x = (int)(lower_bound(f, f + MAXN, n) - f);
if (f[x] == n)
{
return g[x];
}
x--;
return g[x] + F(n - f[x]) + n - f[x];
}
int main()
{
ll n;
int i, T;
f[0] = f[1] = 1;
g[0] = g[1] = 1;
for (i = 2; i < MAXN; i++)
{
f[i] = f[i - 1] + f[i - 2];
g[i] = g[i - 1] + g[i - 2] + f[i - 2] - 1;
}
scanf("%d", &T);
while (T--)
{
scanf("%lld", &n);
printf("%lld\n", F(n));
}
return 0;
}