#include using namespace std; long long total_len(long long n) { long long res = 0; for (long long len = 1, l = 1; l <= n; len++, l <<= 1) { long long r = min(n, (1LL << len) - 1); res += len * (r - l + 1); if (l > n / 2) break; } return res; } int bit_length(int x) { return 32 - __builtin_clz((unsigned)x); } struct RowInfo { int start; int len; int value; }; struct DLX { int nCol; int primaryCols; vector L, R, U, D; vector col, row, sz; vector answer; vector* rowsInfo; long long nodes; long long nodeLimit; int branchLimit; mt19937 rng; chrono::steady_clock::time_point deadline; DLX(int nCol, int primaryCols, int reserveNodes, vector* rowsInfo) : nCol(nCol), primaryCols(primaryCols), rowsInfo(rowsInfo) { int cap = nCol + 1 + reserveNodes; L.reserve(cap); R.reserve(cap); U.reserve(cap); D.reserve(cap); col.reserve(cap); row.reserve(cap); L.resize(nCol + 1); R.resize(nCol + 1); U.resize(nCol + 1); D.resize(nCol + 1); col.resize(nCol + 1); row.resize(nCol + 1, -1); sz.assign(nCol + 1, 0); // 1..primaryCols だけ root list に入れる。 // primary: 文字位置 // secondary: 値 L[0] = primaryCols; R[0] = primaryCols == 0 ? 0 : 1; for (int i = 1; i <= primaryCols; i++) { L[i] = i - 1; R[i] = i == primaryCols ? 0 : i + 1; } for (int i = primaryCols + 1; i <= nCol; i++) { L[i] = R[i] = i; } for (int i = 0; i <= nCol; i++) { U[i] = D[i] = i; col[i] = i; } nodes = 0; nodeLimit = 0; branchLimit = 0; } void add_node(int r, int c, int& first) { int id = (int)col.size(); L.push_back(id); R.push_back(id); U.push_back(U[c]); D.push_back(c); col.push_back(c); row.push_back(r); D[U[c]] = id; U[c] = id; sz[c]++; if (first == -1) { first = id; L[id] = R[id] = id; } else { R[id] = first; L[id] = L[first]; R[L[first]] = id; L[first] = id; } } void add_row(int r, const vector& cols) { int first = -1; for (int c : cols) { add_node(r, c, first); } } void cover(int c) { R[L[c]] = R[c]; L[R[c]] = L[c]; for (int i = D[c]; i != c; i = D[i]) { for (int j = R[i]; j != i; j = R[j]) { D[U[j]] = D[j]; U[D[j]] = U[j]; sz[col[j]]--; } } } void uncover(int c) { for (int i = U[c]; i != c; i = U[i]) { for (int j = L[i]; j != i; j = L[j]) { sz[col[j]]++; D[U[j]] = j; U[D[j]] = j; } } R[L[c]] = c; L[R[c]] = c; } bool time_over() const { return chrono::steady_clock::now() >= deadline; } long long row_score(int nodeId) { int rid = row[nodeId]; const RowInfo& info = (*rowsInfo)[rid]; int valueCol = primaryCols + info.value; long long valueDegree = sz[valueCol]; long long positionDegreeSum = 0; for (int j = nodeId;; j = R[j]) { int c = col[j]; if (c <= primaryCols) { positionDegreeSum += sz[c]; } if (R[j] == nodeId) break; } return valueDegree * 1000000LL + positionDegreeSum * 1000LL + (long long)(rng() % 1000); } bool solve() { if (++nodes > nodeLimit) return false; if ((nodes & 4095) == 0 && time_over()) { return false; } if (R[0] == 0) { return true; } int c = R[0]; for (int j = R[c]; j != 0; j = R[j]) { if (sz[j] < sz[c]) { c = j; } } if (sz[c] == 0) { return false; } vector rows; rows.reserve(sz[c]); for (int i = D[c]; i != c; i = D[i]) { rows.push_back(i); } sort(rows.begin(), rows.end(), [&](int a, int b) { return row_score(a) < row_score(b); }); int lim = branchLimit == 0 ? (int)rows.size() : min(rows.size(), branchLimit); cover(c); for (int k = 0; k < lim; k++) { int i = rows[k]; answer.push_back(row[i]); for (int j = R[i]; j != i; j = R[j]) { cover(col[j]); } if (solve()) { return true; } for (int j = L[i]; j != i; j = L[j]) { uncover(col[j]); } answer.pop_back(); } uncover(c); return false; } }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string C; cin >> C; int L = (int)C.size(); int lo = 1, hi = 65535; while (lo < hi) { int mid = (lo + hi) / 2; if (total_len(mid) >= L) hi = mid; else lo = mid + 1; } if (total_len(lo) != L) { return 0; } int N = lo; int M = bit_length(N); vector rows; vector> rowCols; int reserveNodes = 0; for (int s = 0; s < L; s++) { if (C[s] != '1') continue; int v = 0; for (int len = 1; len <= M && s + len <= L; len++) { v = (v << 1) + (C[s + len - 1] - '0'); if (v > N) break; int t = s + len; if (t < L && C[t] != '1') continue; vector cols; cols.reserve(len + 1); // primary columns: 1..L // 文字位置をちょうど1回覆う。 for (int p = s; p < t; p++) { cols.push_back(p + 1); } // secondary columns: L+1..L+N // 値を高々1回だけ使う。 cols.push_back(L + v); rows.push_back({s, len, v}); rowCols.push_back(move(cols)); reserveNodes += len + 1; } } DLX dlx(L + N, L, reserveNodes, &rows); for (int i = 0; i < (int)rowCols.size(); i++) { dlx.add_row(i, rowCols[i]); } int attempts; int branchLimit; long long nodeLimit; int timeMs = 1900; if (N <= 60) { attempts = 1; branchLimit = 0; // 小さい場合はほぼ正確に解く nodeLimit = 20000000; } else if (N <= 1000) { attempts = 6; branchLimit = 6; nodeLimit = 3000000; } else { attempts = 8; branchLimit = 3; nodeLimit = 1200000; } auto deadline = chrono::steady_clock::now() + chrono::milliseconds(timeMs); vector answerIds; for (int a = 0; a < attempts; a++) { if (chrono::steady_clock::now() >= deadline) break; dlx.answer.clear(); dlx.nodes = 0; dlx.branchLimit = branchLimit; dlx.nodeLimit = nodeLimit; dlx.deadline = deadline; dlx.rng.seed(1234567u + 1000003u * a); if (dlx.solve()) { answerIds = dlx.answer; break; } } if (answerIds.empty()) { return 0; } vector chosen; chosen.reserve(answerIds.size()); for (int id : answerIds) { chosen.push_back(rows[id]); } sort(chosen.begin(), chosen.end(), [](const RowInfo& a, const RowInfo& b) { return a.start < b.start; }); if ((int)chosen.size() != N) { return 0; } for (int i = 0; i < (int)chosen.size(); i++) { if (i) cout << ' '; cout << chosen[i].value; } cout << '\n'; return 0; }