「BZOJ2796」[POI2012] Fibonacci Representation
Description
Fib数列0,1,1,2,3,5,8,13,21。
给出一个数字,用FIB数列各项加加减减来得到。例如
10=5+5
19=21-2
17=13+5-1
1070=987+89-5-1
Input
In the first line of the standard input a single positive integer is given (1 <=P<=10) that denotes the number of queries. The following lines hold a single positive integer K each 1<=K<=10^17.
Output
For each query your program should print on the standard output the minimum number of Fibonacci numbers needed to represent the number k as their sum or difference.
Sample Input
1
1070
1070
Sample Output
4
题解
因为F[k]*2=F[k+1]+F[k-2],即存在最优解满足同一个FIB数出现次数不超过1
令l表示小等于n且最大的斐波那契数,r为其后一项,可以暴力或者二分求
dp(n) = min{ dp(n-l) , dp(r-n) } + 1
使用记忆化搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#include<set> #include<map> #include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define ll long long #define inf 2e18 using namespace std; ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int T,top; ll n,f[1005]; map<ll,int> F; int solve(ll n) { if(F[n])return F[n]; int b=lower_bound(f,f+top,n)-f; if(f[b]==n)return 1; return F[n]=min(solve(n-f[b-1]),solve(f[b]-n))+1; } int main() { f[0]=1;f[1]=1; T=read(); for(int i=2;f[i-1]<=inf;i++,top++) f[i]=f[i-1]+f[i-2]; while(T--) { n=read(); printf("%d\n",solve(n)); } return 0; } |
感谢黄学长!
……我知道了应该把k-1改成k-2