先计算 f [i],保存有 i 个节点的树可有多少个,在每个节点试探左儿子有多少个节点,右儿子有多少节点,然后进行一些细节的计算。
比如得到左儿子节点数后,就知道左儿子是那种树(节点数相同是一种树),这时再计算左儿子应该是这种树中的第几棵。
虽然已经尽量追求代码整洁了,但是代码还是比较丑。。。
#include
#include
#include
#include
#include
#include
#define MAXN 100
long long f [MAXN];
void print_tree (long long n) {
#ifdef _DEBUG
printf ("n = %lld\n", n);
#endif
if (n == 0) {
return;
} else if (n == 1) {
printf ("X");
return;
}
long long nodes = 0;
long long count = 0;
while (count <= n) {
count += f [nodes++];
}
count -= f [--nodes];
long long l_nodes = 0;
long long r_nodes = nodes - 1 - l_nodes;
long long d = 0;
while (count + d <= n) {
d += f [l_nodes++] * f [r_nodes--];
}
d -= f [--l_nodes] * f [++r_nodes];
long long t = n - count - d;
long long l_n = std::accumulate (f, f + l_nodes, 0) + t / f [r_nodes];
long long r_n = std::accumulate (f, f + r_nodes, 0) + t % f [r_nodes];
if (l_n) {
printf ("(");
print_tree (l_n);
printf (")");
}
printf ("X");
if (r_n) {
printf ("(");
print_tree (r_n);
printf (")");
}
}
int main () {
memset (f, 0, sizeof (f));
long long sum = 0;
f [0] = f [1] = 1;
for (int i=2; i 5000000000LL) {
break;
}
}
#ifdef _DEBUG
for (int i=0; i<20; ++i) {
printf ("%lld%s", f [i], i==19 ? "\n" : " ");
}
#endif
long long n;
while (scanf ("%lld", &n) == 1 && n) {
print_tree (n);
printf ("\n");
}
return 0;
}