输入N和N个数(N<=10,每个数<=10^17),对于每个数,要输出能用几个斐波那契数加加减减得到
样例输入:
3
5
10
1070
样例输出:
1
2
4
直接拷题解:
fib[i]表示斐波那契数列的第i项,两个结论:
1.一个数不能出现两次:fib[i]+fib[i]=fib[i-2]+fib[i+1],而fib[2]+fib[2]=fib[3],将出现两次的数不断拆分,答案只会减小不会变大。
2.相邻两项不能同时取:fib[i]-fib[i-1]=fib[i-2],fib[i]+fib[i-1]=fib[i+1],将相邻的数不断拆分,答案只会减小不会变大。
对于一个X,要么本身就是fib数,要么用比X大的最小fib数减掉一个数,要么用比X小的最大fib数来加上一个数。
这个故事告诉我们,求出所有fib数后,直接记忆化搜索就可以了。
上代码:
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> using namespace std; long long n,fib[90],f[10000000],x; int ans(long long x) { int r; if ((x<10000000)&&(f[x]!=0)) return f[x]; for (int i=1;i<=85;i++) if (fib[i]>x) { r=i; break; } if ((fib[r]==x)||(fib[r-1]==x)) { return 1; f[x]=1; } if (x<10000000) { f[x]=min(ans(fib[r-1])+ans(x-fib[r-1]),ans(fib[r])+ans(fib[r]-x)); return f[x];} return min(ans(fib[r-1])+ans(x-fib[r-1]),ans(fib[r])+ans(fib[r]-x)); return f[x]; } int main() { freopen("fib.in","r",stdin); freopen("fib.out","w",stdout); fib[1]=fib[2]=1; cin>>n; for (int i=3;i<=85;i++) fib[i]=fib[i-1]+fib[i-2]; //for (int i=1;i<=85;i++) cout<<fib[i]<<' '; for (int i=1;i<=n;i++) cin>>x,cout<<ans(x)<<endl; //cout<<ans(5); return 0; }