| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| static const long long P = 998244353; |
|
|
| |
| long long Sv[35]; |
|
|
| inline long long computeT(int d, const int* gy) { |
| Sv[0] = 0; |
| for (int j = 0; j < d; j++) { |
| long long c = ((Sv[j] - Sv[gy[j]] + (j - gy[j]) + 1) % P + P) % P; |
| Sv[j + 1] = (Sv[j] + c) % P; |
| } |
| return (Sv[d] + d + 1) % P; |
| } |
|
|
| int main() { |
| ios::sync_with_stdio(false); |
| cin.tie(nullptr); |
|
|
| long long k; |
| cin >> k; |
|
|
| if (k == 1) { |
| cout << "1\nHALT PUSH 1 GOTO 1\n"; |
| return 0; |
| } |
|
|
| long long S = (k - 1) / 2; |
| long long kmodP = k % P; |
|
|
| |
| int exactD = -1, exactG = -1; |
| for (int g = 0; g <= 31; g++) { |
| long long val = S + (1LL << g); |
| if (val > 0 && val <= (1LL << 31) && (val & (val - 1)) == 0) { |
| int d = __builtin_ctzll(val); |
| if (d > g && (exactD < 0 || d < exactD)) { |
| exactD = d; |
| exactG = g; |
| } |
| } |
| } |
| int bestN = (exactD > 0) ? exactD + 1 : 999; |
|
|
| |
| int hillD = -1; |
| int hillGy[35]; |
|
|
| int maxTrialD = min(bestN - 2, 30); |
| mt19937 rng((unsigned)(kmodP * 1000003ULL + 42)); |
|
|
| auto startTime = chrono::steady_clock::now(); |
| auto elapsed_ms = [&]() { |
| return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - startTime).count(); |
| }; |
|
|
| int gy[35]; |
|
|
| |
| |
| |
| |
| int minPossibleD = 1; |
| for (int d = 1; d <= 30; d++) { |
| long long maxT; |
| if (d + 1 < 30) { |
| maxT = (1LL << (d + 1)) - 1; |
| if (maxT < P && kmodP > maxT) { |
| minPossibleD = d + 1; |
| continue; |
| } |
| } |
| break; |
| } |
|
|
| |
| for (int d = max(minPossibleD, 15); d <= maxTrialD; d++) { |
| bool found = false; |
| |
| int timeLimit; |
| if (d <= minPossibleD + 2) timeLimit = 800; |
| else if (d <= minPossibleD + 4) timeLimit = 400; |
| else timeLimit = 100; |
|
|
| |
| if (elapsed_ms() > 1800) timeLimit = min(timeLimit, 50); |
|
|
| int startMs = (int)elapsed_ms(); |
| for (int restart = 0; !found; restart++) { |
| if ((int)elapsed_ms() - startMs > timeLimit) break; |
| memset(gy, 0, sizeof(int) * d); |
| for (int j = 1; j < d; j++) gy[j] = rng() % (j + 1); |
| long long T = computeT(d, gy); |
|
|
| int maxIter = 20000; |
| for (int iter = 0; iter < maxIter; iter++) { |
| if (T == kmodP) { found = true; break; } |
| int j = 1 + rng() % (d - 1); |
| int og = gy[j]; |
| int ng = rng() % (j + 1); |
| if (ng == og) continue; |
| gy[j] = ng; |
| long long nT = computeT(d, gy); |
| long long nd = min((nT - kmodP + P) % P, (kmodP - nT + P) % P); |
| long long od = min((T - kmodP + P) % P, (kmodP - T + P) % P); |
| if (nd <= od) { T = nT; } |
| else { gy[j] = og; } |
| } |
| if (!found) { |
| T = computeT(d, gy); |
| if (T == kmodP) found = true; |
| } |
| if (found) { |
| hillD = d; |
| memcpy(hillGy, gy, sizeof(int) * d); |
| break; |
| } |
| } |
| if (found) break; |
| } |
|
|
| if (hillD > 0 && hillD + 1 < bestN) { |
| bestN = hillD + 1; |
| cout << bestN << "\n"; |
| for (int j = 0; j < hillD; j++) { |
| cout << "POP " << (j+1) << " GOTO " << (j+2) |
| << " PUSH " << (j+1) << " GOTO " << (hillGy[j]+1) << "\n"; |
| } |
| cout << "HALT PUSH 1 GOTO " << bestN << "\n"; |
| return 0; |
| } |
|
|
| if (exactD > 0) { |
| cout << bestN << "\n"; |
| for (int j = 0; j < exactD; j++) { |
| int g = (j == exactD - 1) ? exactG : 0; |
| cout << "POP " << (j+1) << " GOTO " << (j+2) |
| << " PUSH " << (j+1) << " GOTO " << (g+1) << "\n"; |
| } |
| cout << "HALT PUSH 1 GOTO " << bestN << "\n"; |
| return 0; |
| } |
|
|
| |
| { |
| int best_cost = 999; |
| vector<int> best_dep; |
| for (int m = 1; m <= 200; m++) { |
| long long T = S + m; |
| if (T & 1) continue; |
| if (T < 2LL * m) continue; |
| vector<int> bits; |
| for (int b = 1; b <= 40; b++) |
| if ((T >> b) & 1) bits.push_back(b); |
| int pc = (int)bits.size(); |
| if (pc > m) continue; |
| multiset<int> exps(bits.begin(), bits.end()); |
| int cost = 0; |
| for (int b : bits) cost += b; |
| bool valid = true; |
| for (int s = 0; s < m - pc; s++) { |
| auto it = exps.lower_bound(2); |
| if (it == exps.end()) { valid = false; break; } |
| int dd = *it; exps.erase(it); |
| exps.insert(dd-1); exps.insert(dd-1); |
| cost += (dd-2); |
| } |
| if (!valid) continue; |
| int total = cost + 1; |
| if (total < best_cost && total <= 512) { |
| best_cost = total; |
| best_dep.clear(); |
| for (int e : exps) best_dep.push_back(e); |
| } |
| } |
| { |
| long long remaining = S; |
| int total_d = 0; |
| vector<int> depths; |
| while (remaining > 0) { |
| int d = 1; |
| while ((1LL << (d+1)) - 1 <= remaining) d++; |
| depths.push_back(d); |
| total_d += d; |
| remaining -= (1LL << d) - 1; |
| } |
| int total = total_d + 1; |
| if (total < best_cost && total <= 512) { |
| best_cost = total; |
| best_dep = depths; |
| } |
| } |
| cout << best_cost << "\n"; |
| int pos = 1; |
| for (int dd : best_dep) { |
| int start = pos; |
| for (int j = 1; j <= dd; j++) { |
| cout << "POP " << j << " GOTO " << (start+j) << " PUSH " << j << " GOTO " << start << "\n"; |
| pos++; |
| } |
| } |
| cout << "HALT PUSH 1 GOTO " << pos << "\n"; |
| } |
| return 0; |
| } |
|
|