File size: 15,711 Bytes
1fd0050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
#include <iostream>
#include <vector>
#include <string>
#include <map>

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<Instruction> 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<JumpRef> pending_jumps;

// We need to resolve labels
// Map from label_id to instruction index
map<int, int> 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<MainCall> 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<int> 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<pair<int, int>> 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;
}