题目大意:
给出n(n<263),求“很拽的序列”H 的第n个数。
“很拽的序列”定义:
1. H(1)=0。
2. 如果把H中的每个整数x变成x个0后跟x+1,在前面附加上0仍然是H。
H序列的前16项:0,1,0,2,1,1,0,3,0,2,1,1,0,0,0,4
现在我们把定义分割再合并,出来的序列完全一样:
1.h(0)=0。
2.把h(i)中的每个整数x变成x个0后跟x+1,就等于h(i+1)。
3.把所有h(i)连在一起就是H。
我们又可以发现一个规律:
h
(
i
)
=
h
(
i
−
2
)
∗
1
+
h
(
i
−
3
)
+
2
+
.
.
.
+
h
(
0
)
∗
i
−
1
+
(
i
)
h(i)=h(i-2)*1+h(i-3)+2+...+h(0)*i-1+(i)
h(i)=h(i−2)∗1+h(i−3)+2+...+h(0)∗i−1+(i)
(此处乘法表示复制,加法表示连接)
接下来任务变得出奇的简单:只要求出n在h(i)里的i,就可以求出H(n)等于几了。算法是递归,还是回溯法。
代码如下:
#include <iostream>
#include <cstring>
#include <cmath>
#define llong unsigned long long
using namespace std;
llong n,f[66];
llong solve(llong n,int duan,llong len){
if(n>=len-duan+1)return 0;
len-=duan-1;
for(int i=1,j=duan-2;j>0;i++,j--){
if(n>=len-j*f[i-1]){
n=((n-(len-j*f[i-1]))%f[i-1])+1;
return n==f[i-1]?i:solve(n,i,f[i-1]);
}
len=len-j*f[i-1];
}
}
int main(){f[0]=1;
for(int i=1;i<64;i++)
f[i]=f[i-1]*2;
while(cin>>n&&n){
int duan;
for(int i=0;i<64;i++)
if(n<f[i]){duan=i-1;break;}
if(f[duan]==n)cout<<duan<<endl;
else cout<<solve(n,duan+1,f[duan+1])<<endl;
}
return 0;
}
注:此题为什么题目叫“Hendrie序列”,我叫它“很拽的序列”么:因为“Hendrie”和“很拽”谐音,而且这个序列的规律太难发现了,光靠我给出的16个元素无法确定规律,因此它的确很拽!