#include <stdio.h>
#include <stdlib.h>
/* adapted from
http://www-cs-faculty.stanford.edu/~knuth/programs/achain4.w
with some severe loss of efficiency
*/
#define ASK_KNUTH 0
#if ASK_KNUTH
unsigned char knuth[20001] = {0};
#endif
#define N 32
#define NMAX 40000
/* u: upper bounds; l: lower bounds */
int u[N] = {1, 2}, l[N] = {1, 2}, out[N], sum[N], tail[N],
cache[NMAX + 1] = {0, 0, 1}, known = 2, stack;
typedef struct { int *p, v; } save_t;
save_t undo[N*N];
#define replace(u, l, n)\
{ undo[stack].v = *(undo[stack].p = u + l); u[l] = n; stack++;}
#define restore(n)\
while (stack > n) { stack--;*(undo[stack].p) = undo[stack].v; }
void show(int len)
{
int i, n, j;
printf("\033[H");
for (i = 0; i <= len; i++) {
n = l[i], j = 1;
printf("%s%5d %5d\033[m %2d ",
out[i] ? "\033[32m" : "", l[i], u[i], i);
while (j <= n) {
putchar((n & j) ? '#':'_');
j <<= 1;
}
while (j < (1 << 16)) putchar(' '), j *= 2;
n = u[i];
for (j = 1; j <= n; j *= 2)
putchar((n & j) ? '#':'_');
while (j < (1 << 16)) putchar(' '), j*= 2;
putchar('\n');
}
}
/* lower and upper bounds */
int lower(int n, int *up)
{
int i, o, q;
if (n <= 2 || (n <= NMAX && cache[n])) {
if (up) *up = cache[n];
return cache[n];
}
for (i = -1, o = 0; n; n >>= 1, i++)
if (n & 1) o++;
if (up) *up = o + --i;
do { i++; } while (o >>= 1);
if (!up) return i;
for (o = 2; o * o < n; o++) {
if (n % o) continue;
q = cache[o] + cache[n / o];
if (q < *up)
if ((*up = q) == i) break;
}
if (n > 2) {
if (*up > cache[n-2] + 1) *up = cache[n-1] + 1;
if (*up > cache[n-2] + 1) *up = cache[n-2] + 1;
}
return i;
}
int insert(int x, int pos)
{
int save = stack, i, t;
if (l[pos] > x || u[pos] < x) return 0;
if (l[pos] == x) goto repl_u;
replace(l, pos, x);
for (i = pos - 1; u[i] * 2 < u[i+1]; i--) {
if ((t = l[i+1] + 1) * 2 > u[i]) goto bail;
replace(l, i, t);
}
for (i = pos + 1; l[i] <= l[i-1]; i++) {
if ((t = l[i-1] + 1) > u[i]) goto bail;
replace(l, i, t);
}
repl_u: if (u[pos] == x) return 1;
replace(u, pos, x);
for (i = pos - 1; u[i] >= u[i+1]; i--) {
if ((t = u[i+1] - 1) < l[i]) goto bail;
replace(u, i, t);
}
for (i = pos + 1; u[i] > u[i-1] * 2; i++) {
if ((t = u[i-1] * 2) < l[i]) goto bail;
replace(u, i, t);
}
return 1;
bail: restore(save);
return 0;
}
int seq_recur(int);
int seq_len(int);
inline int try_pq(int p, int q, int len) {
int ps, qs, pl, ql, pu, qu, j;
pl = cache[p];
if (pl >= len) return 0;
ql = cache[q];
if (ql >= len) return 0;
while (pl < len && u[pl] < p) pl++;
for (pu = pl - 1; pu < len - 1 && u[pu + 1] >= p; pu++);
while (ql < len && u[ql] < q) ql++;
for (qu = ql - 1; qu < len - 1 && u[qu + 1] >= q; qu++);
if (p != q && pl <= ql) pl = ql + 1;
if (pl > pu || ql > qu || ql > pu) return 0;
if (!out[len]) pl = pu = len - 1;
ps = stack;
for (; pu >= pl; pu--) {
if (!insert(p, pu)) continue;
out[pu]++, sum[pu] += len;
if (p != q) {
qs = stack;
j = qu;
if (j >= pu) j = pu - 1;
for (; j >= ql; j--) {
if (!insert(q, j)) continue;
out[j]++, sum[j] += len, tail[len] = q;
if (seq_recur(len - 1)) return 1;
restore(qs);
out[j]--, sum[j] -= len;
}
} else {
out[pu]++, sum[pu] += len, tail[len] = p;
if (seq_recur(len - 1)) return 1;
out[pu]--, sum[pu] -= len;
}
out[pu]--, sum[pu] -= len;
restore(ps);
}
return 0;
}
int seq_recur(int len)
{
int p, q, n, limit;
n = l[len];
if (len < 2) return 1;
limit = out[len] == 1 ? n - tail[sum[len]] : n - 1;
if (limit > u[len - 1]) limit = u[len - 1];
/* try to break n into p + q, and see if we can insert p, q into
list while satisfying bounds */
for (p = limit, q = n - p; q <= p; q++, p--)
if (try_pq(p, q, len)) return 1;
return 0;
}
int seq(int n, int len, int *buf)
{
int i;
if (!len) len = seq_len(n);
stack = 0;
u[len] = l[len] = n;
for (i = 0; i <= len; i++) out[i] = sum[i] = 0;
for (i = 2; i < len; i++) {
l[i] = l[i-1] + 1;
u[i] = u[i-1] * 2;
}
for (i = len - 1; i > 2; i--) {
if (l[i] * 2 < l[i+1]) l[i] = (1 + l[i+1]) / 2;
if (u[i] >= u[i+1]) u[i] = u[i+1] - 1;
}
if (!seq_recur(len)) return 0;
if (buf) for (i = 0; i <= len; i++) buf[i] = u[i];
return len;
}
int seq_len(int n)
{
int lb, ub;
if (n <= known) return cache[n];
/* need all lower n to compute sequence */
while (known + 1 < n)
seq_len(known + 1);
lb = lower(n, &ub);
while (lb < ub && !seq(n, lb, 0)) ++lb;
#if ASK_KNUTH
if (n < 20000 && lb != knuth[n] - 32) {
printf("bad %d: %d %d\n", n, lb, knuth[n] - 32);
fflush(stdout);
abort();
}
#endif
known = n;
if (!(n & 1023))
fprintf(stderr, "cached %d\n", known);
return cache[n] = lb;
}
void init(void) {
#if ASK_KNUTH
FILE *fp = fopen("out", "r");
fread(knuth + 1, 1, 20000, fp);
fclose(fp);
#endif
}