题目

数列 Sn 如下定义:

  • S1 是一个只含有 11 的长度为 1 的数列
  • Sn 是按照 Sn1,n,Sn1 的顺序连接得到

下面以 S2,S3 为例:

S2 是由 S1,2,S1 连接得到,因为 S11 个数 1,所以 S21,2,1
S3 是由 S2,3,S2 连接得到,所以 S31,2,1,3,1,2,1

给出 nk,输出 Sn 的第 k 个数。

限制:

  • 1n641k2641k 不超过 Sn 的长度。

注意 k 可能超过 64 位有符号整数类型范围,需要使用 64 位无符号整数类型。

算法分析

要找 Sn 的第 k 个数可化为 Sn1 中的某数的问题
用递归

f(n, k) 表示返回 Sn 中第 k 个数的值

Sn-1 n Sn-1
前 中 后

L[n-1]Sn1 的长度
kL[n1],则说明在前面,返回 f(n-1, k)
kL[n1]+2,则说明在后面,返回 f(n-1, k-L[n-1]-1)
k=L[n1]+1,则说明在正中间,返回 n

L[i] 表示 Si 的长度
递推式:L[i]=2L[i1]+1
通项:L[i]=2i1

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ull = unsigned long long;
int main(){
int n;
ull k;
cin >> n >> k;
vector<ull> l(n+1);
rep(i, n) l[i+1] = 2*l[i] + 1;
auto f = [&](auto& f, int n, ull k) -> int {
if (k <= l[n-1]) return f(f, n-1, k);
if (k >= l[n-1]+2) return f(f, n-1, k-l[n-1]-1);
if (k == l[n-1]+1) return n;
};
int ans = f(f, n, k);
cout << ans << '\n';
return 0;
}