NC15979 小q的数列

题目

题目描述

小q最近迷上了各种好玩的数列,这天,他发现了一个有趣的数列,其递推公式如下:

\[f[i] = \left\{ \begin{array}{l} 0 ,& i = 0\\ 1 ,& i=1\\ f[i/2]+f[i\%2],& i\geq 2 \end{array} \right. \]

现在,他想考考你,问:给你一个 \(n\) \((n<10^{18})\),代表数列的第 \(n\) 项,你能不能马上说出 \(f[n]\) 的值是多少,以及 \(f[n]\) 所代表的值第一次出现在数列的哪一项中?

输入描述

输入第一行一个 \(t\)
随后 \(t\) 行,每行一个数 \(n\) ,代表你需要求数列的第 \(n\) 项,和相应的 \(n'\)
\((t<4 \cdot 10^5)\)

输出描述

输出每行两个正整数
\(f[n]\)\(n'\) ,以空格分隔

示例1

输入

2
0
1

输出

0 0
1 1

题解

知识点:递归,数学。

按公式递归求值不难,接下来证明求最小 \(n'\)

若把 \(n\) 看成二进制,公式可理解为 \(f[n>>1] + f[n\&1]\) ,即对于每位如果为 \(1\) 则加 \(1\) ,因此 \(f[n]\) 的结果是 \(n\) 二进制位为 \(1\) 的数量。那么一个数 \(n'\)\(f[n']\)与 $f[n] $ 相同而且要最小,只要把 \(f[n]\)\(1\) 从低位到高位排列,就能构造 \(n'\)。所以,\(n' = 2^{f[n]-1}\)

时间复杂度 \(O(\log n)\)

空间复杂度 \(O(1)\)

代码

#include <bits/stdc++.h>

using namespace std;

int f(long long n) {
    if (n == 0 || n == 1) return n;
    return f(n / 2) + f(n % 2);
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        long long n;
        cin >> n;
        int ans = f(n);
        cout << ans << ' ' << ((1LL << ans) - 1) << '\n';
    }
    return 0;
}
posted @ 2022-06-22 22:01  空白菌  阅读(80)  评论(0编辑  收藏  举报