题解:
1、模拟前十个数据可以发现几个规律
2、首先根据亦或的原理对数据进行二进制计算,发现符合条件的数都不允许1连续,但允许0连续
3、然后发现,在符合条件的数据中,每增加一位,都是一个斐波那契数列(即两个0时一共有2个数,五个0时5)
4、然后对查询数进行拆分成2的多少次方
5、在拆分的数据中如果数据和边缘相等,和大于边缘的情况分别处理以下即可
6、注意pow太多的话会发生段错误,所以预先把2的次方存下来,一方面防止段错误,一方面降低时间复杂度
#include <bits/stdc++.h>
using namespace std;
const int maxn = 70;
long long fib[maxn];
long long tpow[maxn];
void init(){
fib[0] = 1;
fib[1] = 1;
for(int i = 2; i < 60; i++)
fib[i] = fib[i-1] + fib[i-2];
tpow[0] = 1;
for(int i = 1; i < 65; i++)
tpow[i] = tpow[i-1] << 1;
}
void slove(){
long long n;
unsigned long long cnt = 0;
scanf("%lld",&n);
while(n>0){
int i = 0;
long long sum = 0;
while(sum + fib[i] <= n)
sum += fib[i++];
n = n - sum;
if(n == 0){
n = n - sum;
for(int j = i - 1; j >= 0; j = j - 2)
cnt += tpow[j];
}
else {
n = n - 1;
cnt += tpow[i];
}
}
printf("%lld\n",cnt);
}
int main(){
int t;
init();
scanf("%d",&t);
for(int i = 0; i < t; i++)
slove();
return 0;
}