BZOJ2796/POI2012 Fibonacci Representation

Task
Fib数列0,1,1,2,3,5,8,13,21。
给出一个数字,用FIB数列各项加加减减来得到。例如
10=5+5
19=21-2
求出通过加减得到K的最少项数.
1<=K<=10^17.

Solution
有一个贪心的思路,每次找到离K最近的两项f(i),f(i+1),再把问题转化为求K-f(i),f(i+1)-K即可.用计划搜索优化.我是将10^7以内的数字直接用数组存下来,不过发现效率远没有用map存下所有值的高.T_T

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define ll long long
#include<queue>
using namespace std;
inline void rd(int &res){
    res=0;char c;
    while(c=getchar(),c<48);
    do res=(res<<1)+(res<<3)+(c^48);
    while(c=getchar(),c>=48);
}
inline void print(ll x){
    if(!x)return ;
    print(x/10);
    putchar((x%10)^48);
}
inline void sc(ll x){
    if(x<0){x=-x;putchar('-');}
    print(x);
    if(!x)putchar('0');
    putchar('\n');
}
const ll M=1e18;
const int N=1e7+3e6+5;
ll A[200],K;
int tot=89,f[N];
void Init(){
    A[1]=1;A[2]=1;
    for(int i=3;i<tot;i++)A[i]=A[i-1]+A[i-2];
}
int solve(ll x,int r){
    if(x<N&&~f[x])return f[x];
    int ans,a=lower_bound(A,A+r,x)-A;
    if(A[a]==x)ans=1;
    else ans=1+min(solve(x-A[a-1],a-2),solve(A[a]-x,a-2));
    if(x<N)f[x]=ans;
    return ans;
}
int main(){
    int i,j,cas,a,b,mx=0,m=0;
    Init();
    memset(f,-1,sizeof(f));
    scanf("%d",&cas);
    while(cas--){
        cin>>K;
        printf("%d\n",solve(K,tot));
    }
    return 0;
}

没有更多推荐了,返回首页