题目链接: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;
}