Nowcoder 105D Fibonacci 进制 (数论)

版权声明:------------------- 这是千千的个人网站哦! https://www.dreamwings.cn ------------------- https://blog.csdn.net/qq_28954601/article/details/80105422

题目描述

Fibonacci 数是非常有名的一个数列,它的公式为 f(n)=f(n1)+f(n2),f(0)=1,f(1)=2

我们可以把任意一个数 x 表示成若干不相同的 Fibonacci 数的和,比如说 14=13+1=8+5+1=8+3+2+1

如果把 Fibonacci 数列作为数的位权,即 f(i) 作为第 i 位的位权,每位的系数只能是 0 或者 1 ,从而得到一个 01 串。比如 14 可以表示成 100001,11001,10111 。 我们再把这个 01 串看成 2 进制,再转成 10 进制以后就变成了 33,25,23 。为了避免歧义,我们将使用最小的那个值 23

请按照这个过程计算一下 10 进制整数通过上述转换过程得到的 10 进制整数。

 

输入描述

第一行是一个整数 T(1T10000) ,表示样例的个数。

以后每行一个样例,为一个十进制正整数 x(1x109)

 

输出描述

每行输出一个样例的结果。

 

输入

5
1
10
100
1000
1000000000

 

输出

1
14
367
10966
4083305275263

 

思路

因为我们要让这一个数 x 表示的最终结果最小,所以要将他展开的越彻底越好(注意不能出现相同的斐波那契数)

最好的情况下 x 刚好可以表示为前 k 项的斐波那契数的和减一(因为标准的斐波那契数列前面有两个重复的 1

于是我们有:

x=(i=1kFibonacci[i])1

根据斐波那契数列的性质我们还有:
i=1nFibonacci[i]=Fibonacci[n+2]1

因此得出:
x=Fibonacci[k+2]2

等价于:
x+2=Fibonacci[k+2]

打表得出 109 以内所有的斐波那契数,然后二分求出一个 k 使得 Fibonacci[k+2]x+2

  • 对于特殊的情况( Fibonacci[k+2]=x+2 ):显然此时的答案等于 2k1
  • 对于一般的情况( Fibonacci[k+2]>x+2 ):我们需要从中去除可以组合出 Fibonacci[k+2](x+2) 的极大项(常识不加解释),最终所剩余的部分便是这道题的答案

 

AC 代码

#include <bits/stdc++.h>
#define IO                       \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout.tie(0);
using namespace std;
typedef long long LL;
const int maxn = 1e5 + 10;

LL f[52] = {
    1,          1,           2,           3,           5,          8,
    13,         21,          34,          55,          89,         144,
    233,        377,         610,         987,         1597,       2584,
    4181,       6765,        10946,       17711,       28657,      46368,
    75025,      121393,      196418,      317811,      514229,     832040,
    1346269,    2178309,     3524578,     5702887,     9227465,    14930352,
    24157817,   39088169,    63245986,    102334155,   165580141,  267914296,
    433494437,  701408733,   1134903170,  1836311903,  2971215073, 4807526976,
    7778742049, 12586269025, 20365011074, 32951280099,
};

void solve(LL x) {
    LL now = lower_bound(f, f + 52, x + 2) - f;
    LL cha = f[now] - x - 2;
    now = (1LL << (now - 2)) - 1;
    while (cha > 0) {
        LL sn = upper_bound(f, f + 52, cha) - 1 - f;
        now &= ~(1LL << (sn - 1));
        cha -= f[sn];
    }
    cout << now << endl;
}

int main() {
#ifdef LOCAL_IM0QIANQIAN
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#else
    IO;
#endif // LOCAL_IM0QIANQIAN
    int T;
    cin >> T;
    while (T--) {
        LL x;
        cin >> x;
        solve(x);
    }
    return 0;
}
阅读更多
换一批

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