题目链接:https://www.nowcoder.com/acm/contest/105/D

       这道题如果单纯用搜索的话会TLE,可以换一种方法,因为要找的是组成的二进制数最小的十进制(尽量让最高位尽量小),首先在初始化的时候求出这个数列的前缀和,然后找到第一个大于等于m的前缀和的位置,则这个位置的斐波那契值肯定是可以取的,标记二进制数的这个位置为1,不好理解,结合代码想一下。然后根据得到的二进制得出最后的值。


TLE代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
ll n,m;
ll pre[55];
int p[55];
ll ans;
int flag;

void init(){
  pre[0] = 1;
  pre[1] = 2;
  for(int i=2;i<=50;i++){
    pre[i] = pre[i-1] + pre[i-2];
  }
}

void dfs(int x,int sum){
  if(sum == m){
    ll temp = 0;
    if(m==1)p[0] = 1;
    for(int i=0;i<=50;i++){
      temp += (p[i] * pow(2,i));
    }
    ans = min(ans,temp);
    flag = 1;
  }
  if(flag)return ;
  if(sum > m)return ;
  for(int i=x;i<=50;i++){
    if(sum + pre[i] <= m && ){
      p[i] = 1;
      dfs(i + 1, sum + pre[i]);
      p[i] = 0;
      if(flag)return ;
    }
  }
}

int main()
{
  init();
  scanf("%lld",&n);
  while(n--){
    scanf("%lld",&m);
    ans = 4083305275263;
    flag = 0;
    memset(p,0,sizeof(p));
    dfs(0,0);
    printf("%lld\n",ans);
  }
  return 0;
}


AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
ll n;
ll pre[55],s[55];
int p[55];

void init(){
  pre[0] = 1;
  pre[1] = 2;
  s[0] = 1;
  s[1] = 3;
  for(int i=2;i<50;i++){
    pre[i] = pre[i-1] + pre[i-2];
    s[i] = s[i-1] + pre[i];
  }
  return ;
}

int main()
{
  init();
  scanf("%lld",&n);
  while(n--){
    ll temp;
    scanf("%lld",&temp);
    memset(p,0,sizeof(p));
    for(int i=49;i>=1;i--){
      if(temp > s[i-1]){
        temp -= pre[i];
        p[i] = 1;
      }
    }
    ll ans = 0;
    if(temp == 1)p[0] = 1;
    for(int i=0;i<49;i++){
      ans += (p[i] * pow(2,i));
    }
    printf("%lld\n",ans);
  }
  return 0;
}