一道神奇的数学题……
首先需要了解:将一个数每次减去最大可减的斐波那契数,一定是最优的方案之一
以下用 fi 表示斐波那契数列的第i项
则有:
Gfi−1=Gfi−1−1+Gfi−fi−1−1+fi−fi−1⇒Gfi−1=Gfi−1−1+Gfi−2−1+fi−2
于是我们可以预处理出 fi ,以及 Gi 的一些特殊位置
现在询问任意
Gn
(以下记为
Sum(n)
),其实一样的思路,设
m
为小于
Sum(n)=Sum(n−m)+n−m+1+Gm
由于斐波那契数列是接近于指数增长的,所以可以看做 O(log2n) 的复杂度(二分找m O(logn) )
当然,程序实现时用 Gi 代表 Gfi−1
示例程序:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=105;
typedef long long LL;
LL tst,n,nn,f[maxn],G[maxn];
LL sum(LL n){
if (n<=3) return n;
int i=upper_bound(f,f+1+nn,n)-f-1;
return G[i]+sum(n-f[i])+n-f[i]+1;
}
int main(){
f[0]=0;f[1]=f[2]=1;f[3]=2;
G[1]=G[2]=0;G[3]=1;
for (int i=4;;i++){
f[i]=f[i-1]+f[i-2];
G[i]=G[i-1]+G[i-2]+f[i-2];
if (f[i]>1e17) {nn=i;break;}
}
scanf("%lld",&tst);
while (tst--)
scanf("%lld",&n),printf("%lld\n",sum(n));
return 0;
}