#include #include #include #include using namespace std; struct Instruction { string type; // "POP" or "HALT" int a; // only for POP int x; // goto x int b; // push b int y; // goto y }; vector program; int add_instruction(string type, int a, int x, int b, int y) { program.push_back({type, a, x, b, y}); return program.size(); } // Placeholders for jumps struct JumpRef { int instr_idx; bool is_x; // true if fixing x, false if fixing y }; vector pending_jumps; // We need to resolve labels // Map from label_id to instruction index map labels; int get_label_addr(int id) { return labels[id]; } void set_label(int id, int addr) { labels[id] = addr; } // Logic for level j // We have levels 0 to 29. // Each level j has: // Start_0 (Entry for state 0) // Start_1 (Entry for state 1) // Mid_0 (Return point from child for state 0) // Point_0_Switch (Transition 0->1) // Mid_1 (Return point from child for state 1) // Exit_0 (Dispatcher) -- actually exit logic is shared or sequenced // Wait, Exit logic is part of the flow. // We need distinct return points for child calls. // Params for Level j struct Level { long long cost; int val_0; int val_1; // Labels int label_start_0; int label_mid_0; // Return from first child call int label_point_1; // Start of state 1 flow int label_mid_1; // Return from second child call int label_end; // Exit dispatcher }; Level levels[31]; // Main callers need markers struct MainCall { int level_idx; int marker; int return_label; }; vector main_calls; int main() { long long K; if (!(cin >> K)) return 0; if (K == 1) { cout << "1\nHALT PUSH 1 GOTO 1" << endl; return 0; } // Costs: W_j = 7 * 2^j - 5 // j from 0 to 29 for (int j = 0; j <= 29; ++j) { levels[j].cost = (7LL << j) - 5; levels[j].val_0 = 2 * j + 1; levels[j].val_1 = 2 * j + 2; levels[j].label_start_0 = 1000 * j + 1; levels[j].label_mid_0 = 1000 * j + 2; levels[j].label_point_1 = 1000 * j + 3; levels[j].label_mid_1 = 1000 * j + 4; levels[j].label_end = 1000 * j + 5; } // Decompose K-1 long long target = K - 1; vector blocks; // Greedy decomposition // Since we only have W_0=2 (even) and others odd, we need to be careful with parity. // However, since we can pick W_0 multiple times, and W_1... are odd. // Actually, we can just use small blocks for small values. // But W_0=2 is the only even block. // If target is odd, we MUST use at least one odd block. // If target is even, we can use 0 odd blocks or even number of odd blocks. while (target > 0) { int best_j = -1; for (int j = 29; j >= 0; --j) { if (levels[j].cost <= target) { // Check parity constraint? // If we take this block, new_target = target - cost. // We need to be able to solve new_target. // If new_target is odd, we need at least one odd block <= new_target. // Smallest odd is W_1 = 9. // If new_target is odd and < 9, we are stuck (can't represent 1,3,5,7). // Note: W_0=2. // So "bad" states are odd numbers < 9. long long rem = target - levels[j].cost; if (rem % 2 != 0 && rem < 9) { continue; // Don't take this } best_j = j; break; } } if (best_j == -1) { // Should not happen given 2 and 9 cover everything eventually // But for very small odd target < 9? // Initial K is odd => target K-1 is even. // If we maintain target even, we pick even blocks? Only W_0=2. // If we pick odd block, target becomes odd. Then we pick another odd block -> even. // Just need to avoid remainder being small odd. // If we are stuck, it's logic error. break; } blocks.push_back(best_j); target -= levels[best_j].cost; } // Assign markers for main calls int marker_counter = 600; for (int b : blocks) { MainCall mc; mc.level_idx = b; mc.marker = marker_counter++; mc.return_label = marker_counter++; // Label ID for return point main_calls.push_back(mc); } // 1. Generate Main Loop int main_start_label = 90000; set_label(main_start_label, program.size() + 1); // Initial Push Marker 0 (Dummy) ? No, main calls structure: // PUSH Marker -> Call -> Ret -> Next // But first instruction must be special? // "The interpreter starts... reads the first instruction." // Input K>1. First instr: POP ... PUSH b GOTO y. // Stack empty -> Pushes b, GOTO y. // We will structure main as: // Instr 1: POP 999 GOTO Halt_Label PUSH First_Marker GOTO First_Call_Start // The "POP 999" is just dummy to force PUSH branch initially. // But wait, after first block returns, we are at Return_Label. // We need to proceed to next block. // Let's chain them. // Block 0: Push Marker0, Goto Start_Block0. // Return_Point_0: Push Marker1, Goto Start_Block1. // ... // Last Return Point: HALT. // Instruction 1 must coincide with start of Block 0 logic. // Instr 1: POP Dummy GOTO ... PUSH M0 GOTO Start0. int dummy_pop = 999; // We need to setup the main chain labels for (size_t i = 0; i < main_calls.size(); ++i) { int lvl = main_calls[i].level_idx; int m = main_calls[i].marker; int ret_lbl = main_calls[i].return_label; int start_lbl = levels[lvl].label_start_0; // The instruction that calls this block: // If i == 0, this is the entry point (Index 1). // It fails POP (stack empty), Pushes Marker, Jumps to Level Start. // If i > 0, we arrive here from previous return. // We define the label for this point as previous return label. if (i > 0) { set_label(main_calls[i-1].return_label, program.size() + 1); // This instruction is executed after previous block returns. // Previous block popped its marker. Stack is empty? // Wait. Main stack logic: // Empty -> Push M0 -> Run -> Pop M0 -> Empty. // So stack is empty here. // We need to Push M1 and run. // So: POP Dummy GOTO ... PUSH M1 GOTO Start1. add_instruction("POP", dummy_pop, 0, m, 0); // Jump fixups later. x is unused (never popped dummy). // y is start_lbl. pending_jumps.push_back({(int)program.size()-1, false}); // fix y // Map the jump to start_lbl // Actually we can just store the target label id in pending // But we need a separate struct or reuse. // Let's just resolve y = get_label_addr(start_lbl) later. // We'll store label ID in y temporarily? No, y is int. program.back().y = start_lbl; // Store ID, resolve later } else { // First instruction add_instruction("POP", dummy_pop, 0, m, 0); program.back().y = start_lbl; // The jump x is irrelevant as stack empty. // But to be valid, x must point somewhere. Point to 1. program.back().x = 1; } } // Halt logic if (!main_calls.empty()) { set_label(main_calls.back().return_label, program.size() + 1); } else { // Should not happen for K > 1 } // Final instruction: HALT int halt_idx = program.size() + 1; add_instruction("HALT", 0, 0, 1, halt_idx); // args ignored except PUSH/GOTO if stack non-empty (won't happen) program.back().y = halt_idx; // Self loop if not empty // 2. Generate Levels 0..29 for (int j = 0; j <= 29; ++j) { Level& L = levels[j]; // Start 0 set_label(L.label_start_0, program.size() + 1); if (j == 0) { // Level 0 State 0: Cost 2. // Start: POP V_00 GOTO Push1 ... (Fail check) -> PUSH V_01 GOTO Mid // Actually POP fails on V_00? No, Start expects V_00. // We want to consume 1 step and switch to V_01. // So we need POP to FAIL. // POP (!V_00) ... PUSH V_01 GOTO Mid add_instruction("POP", L.val_1, 0, L.val_1, 0); // Check V_01 (Top is V_00). Fail. Push V_01. program.back().x = 1; // Dummy program.back().y = L.label_mid_0; // Goto Mid (which handles V_01) } else { // Level j > 0 State 0 // Push (j-1)_0, Goto Start (j-1)_0 // POP V_j1 (Fail) PUSH V_(j-1)0 GOTO Start_(j-1)0 add_instruction("POP", L.val_1, 0, levels[j-1].val_0, 0); program.back().x = 1; program.back().y = levels[j-1].label_start_0; } // Mid 0 (Return from child 1) set_label(L.label_mid_0, program.size() + 1); if (j == 0) { // Level 0 State 1 (at Mid): Cost 1 step to pop and exit. // POP V_01 GOTO Exit add_instruction("POP", L.val_1, 0, 1, 0); // Pop success. program.back().x = L.label_end; program.back().y = 1; // Dummy } else { // Level j > 0: Returned from (j-1)_0. Stack is V_j0. // Switch to V_j1. // POP V_j0 GOTO Push1 ... // Push1: PUSH V_j1 GOTO Point1 // Instruction at label_mid_0: add_instruction("POP", L.val_0, 0, L.val_1, 0); // Pop V_j0. Success. // Goto Push1. Push1 is next instruction. program.back().x = program.size() + 2; program.back().y = 1; // Dummy // Push1 add_instruction("PUSH", L.val_1, 0, 0, 0); // Push V_j1 program.back().y = L.label_point_1; program.back().x = 1; // Dummy (PUSH type uses HALT format? No, PUSH is ELSE of POP or Explicit?) // Wait, "POP a GOTO x PUSH b GOTO y". // To just PUSH, we need condition to fail. // But here we arrived from successful POP V_j0. // So stack is whatever below V_j0 (Val of caller). // We want to Push V_j1. // We can check POP (Caller)? No caller varies. // Check POP (Impossible Value)? // Val is <= 1024. Use 1025? No limit 1024. // Use something we know is not there? // Caller val is V_j+1 or Marker. // V_j0 is 2j+1. // We can check POP V_j0 again? It was just popped. // So check POP V_j0. Will fail. // Else Push V_j1 Goto Point1. // Modify previous instruction to jump here? // No, the previous was "POP V_j0 GOTO x". // At x, stack has Caller Val. // We put "POP V_j0 ..." at x. // Re-write Mid 0 logic: // Instr 1 (Mid0): POP V_j0 GOTO Instr2 PUSH ... (Dummy). // Instr 2: POP V_j0 (Fail) GOTO ... PUSH V_j1 GOTO Point1. // Correct. // But wait, can we combine? // We want: Pop V_j0, Push V_j1, Goto Point1. // Is it possible in 1 instr? // "POP a ... PUSH b ..." -> Pop a if match, Push b if not. // Cannot do both. // So 2 instructions needed. // Correct code at program.back().x (Next instr): int instr2_idx = program.size() + 1; // Previous instr already points x to instr2_idx. add_instruction("POP", L.val_0, 0, L.val_1, 0); program.back().x = 1; // Should not happen program.back().y = L.label_point_1; } if (j > 0) { // Point 1 (Start of second child call) set_label(L.label_point_1, program.size() + 1); // Stack has V_j1. // Push (j-1)_0. Goto Start (j-1)_0. // POP V_j0 (Fail) PUSH (j-1)_0 ... add_instruction("POP", L.val_0, 0, levels[j-1].val_0, 0); program.back().x = 1; program.back().y = levels[j-1].label_start_0; // Mid 1 (Return from second child call) set_label(L.label_mid_1, program.size() + 1); // Stack has V_j1. // Pop V_j1. Goto End. add_instruction("POP", L.val_1, 0, 1, 0); program.back().x = L.label_end; program.back().y = 1; } // Exit Dispatcher set_label(L.label_end, program.size() + 1); // We need to check callers. // List of Callers: // 1. Level j+1 (if j<29). It calls from State 0 and State 1. // State 0 of j+1 expects return to Mid_0 of j+1. // State 1 of j+1 expects return to Mid_1 of j+1. // Caller 0 val: V_(j+1)0. Caller 1 val: V_(j+1)1. // 2. Main Calls. vector> dispatch_targets; if (j < 29) { dispatch_targets.push_back({levels[j+1].val_0, levels[j+1].label_mid_0}); dispatch_targets.push_back({levels[j+1].val_1, levels[j+1].label_mid_1}); } for (const auto& mc : main_calls) { if (mc.level_idx == j) { dispatch_targets.push_back({mc.marker, mc.return_label}); } } // Generate chain of checks // Each check: POP Val GOTO Restore PUSH Val GOTO NextCheck // Restore: PUSH Val GOTO Target // We can optimize Restore: // POP Val GOTO Target ... // But Target expects Val on stack! // If we POP Val, we remove it. // We need to jump to a PUSH. // "POP Val GOTO Restore ..." // Restore: "POP (Dummy) GOTO ... PUSH Val GOTO Target" for (size_t k = 0; k < dispatch_targets.size(); ++k) { int val = dispatch_targets[k].first; int tgt = dispatch_targets[k].second; // Check instruction int check_idx = program.size() + 1; int restore_idx = check_idx + 1; int next_check_idx = check_idx + 2; // Last one doesn't need next check (assumed guaranteed match) add_instruction("POP", val, 0, val, 0); program.back().x = restore_idx; program.back().y = (k == dispatch_targets.size() - 1) ? 1 : next_check_idx; // Restore instruction add_instruction("POP", dummy_pop, 0, val, 0); // Pop dummy(fail) -> Push val -> Goto Tgt program.back().x = 1; program.back().y = tgt; } } // Resolve Labels cout << program.size() << endl; for (const auto& instr : program) { int final_x = instr.x; int final_y = instr.y; // If x or y looks like a label ID (large number), resolve it if (final_x >= 1000) final_x = get_label_addr(final_x); if (final_y >= 1000) final_y = get_label_addr(final_y); if (instr.type == "HALT") { cout << "HALT PUSH " << instr.b << " GOTO " << final_y << endl; } else { cout << "POP " << instr.a << " GOTO " << final_x << " PUSH " << instr.b << " GOTO " << final_y << endl; } } return 0; }