File size: 6,574 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
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

struct Instruction {
    string type; // "POP" or "HALT"
    int a;       // if POP: value to match. if HALT: unused
    int x;       // goto if match/halt
    int b;       // push value
    int y;       // goto else
};

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();
}

const int UNKNOWN = -1;

struct Layer {
    string type; // "Base", "Linear", "Double7", "Double9"
    int val_in;  // Value expected on stack
    int val_aux; // Second value for Double
    int val_garbage; // Garbage value
    int entry_instr;
    int return_target; // Where this layer returns to (in parent)
};

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    long long k;
    if (!(cin >> k)) return 0;

    if (k == 1) {
        cout << "1\nHALT PUSH 1 GOTO 1\n";
        return 0;
    }

    // We construct a program that executes Preamble + Body + Halt.
    // Preamble takes 1 step. Halt takes 1 step.
    // So Body needs to take t = k - 2 steps.
    long long t = k - 2;
    
    // Decompose t into layers
    vector<string> layer_types;
    
    // While t is large enough to use Double block (min cost 9)
    while (t >= 9) {
        // If t % 4 == 1, then (t - 7)/2 is odd. Use Double7.
        // If t % 4 == 3, then (t - 9)/2 is odd. Use Double9.
        if (t % 4 == 1) {
            layer_types.push_back("Double7");
            t = (t - 7) / 2;
        } else {
            layer_types.push_back("Double9");
            t = (t - 9) / 2;
        }
    }
    
    // Remaining t < 9. Must be odd.
    // Use Linear blocks (+2 steps) to reduce to Base (1 step).
    while (t > 1) {
        layer_types.push_back("Linear");
        t -= 2;
    }
    layer_types.push_back("Base");
    
    // We want the vector to be [Base, Linear, ..., Outermost]
    reverse(layer_types.begin(), layer_types.end());
    
    // Assign values
    int current_val = 1;
    vector<Layer> layers(layer_types.size());
    // Assign from Outermost to Innermost so values are consistent?
    // Actually order doesn't matter as long as values are distinct.
    for (int i = layer_types.size() - 1; i >= 0; --i) {
        layers[i].type = layer_types[i];
        layers[i].val_in = current_val++;
        if (layers[i].type == "Double7" || layers[i].type == "Double9") {
            layers[i].val_aux = current_val++;
            layers[i].val_garbage = current_val++;
        }
    }
    
    int next_instr = 1; 
    
    // Preamble
    int preamble_idx = next_instr++;
    add_instruction("HALT", 0, 0, 0, 0); 
    
    // Final Halt
    int final_halt_idx = next_instr++;
    add_instruction("HALT", 0, 0, 1, 1);
    
    // Generate code for layers (Innermost first)
    for (int i = 0; i < layers.size(); ++i) {
        int child_entry = (i > 0) ? layers[i-1].entry_instr : -1;
        
        if (layers[i].type == "Base") {
            layers[i].entry_instr = next_instr++;
            add_instruction("POP", layers[i].val_in, UNKNOWN, layers[i].val_in, UNKNOWN);
        }
        else if (layers[i].type == "Linear") {
            int start_idx = next_instr++;
            layers[i].entry_instr = start_idx;
            // PUSH child_val GOTO Child_Entry
            add_instruction("POP", layers[i].val_in, UNKNOWN, layers[i-1].val_in, child_entry);
            
            int check_idx = next_instr++;
            add_instruction("POP", layers[i].val_in, UNKNOWN, 1, 1);
            
            program[start_idx-1].x = check_idx;
            layers[i-1].return_target = check_idx;
        }
        else { // Double7 or Double9
            int X = layers[i].val_in;
            int Y = layers[i].val_aux;
            int G = layers[i].val_garbage;
            int child_val = layers[i-1].val_in;
            
            int start_idx = next_instr++;
            layers[i].entry_instr = start_idx;
            
            int check_idx = next_instr++;
            int swap_idx = next_instr++;
            int pass2_idx = next_instr++;
            int cleanup_idx = next_instr++;
            int finish_idx = next_instr++;
            
            int delay_idx = -1, restore_idx = -1;
            if (layers[i].type == "Double9") {
                delay_idx = next_instr++;
                restore_idx = next_instr++;
            }
            
            int else_target = (layers[i].type == "Double9") ? delay_idx : cleanup_idx;
            
            add_instruction("POP", Y, check_idx, child_val, child_entry); // Start
            add_instruction("POP", X, swap_idx, G, else_target);          // Check
            add_instruction("HALT", 0, 0, Y, pass2_idx);                  // Swap
            add_instruction("POP", X, 0, child_val, child_entry);         // Pass2
            add_instruction("POP", G, finish_idx, 0, 0);                  // Cleanup
            add_instruction("POP", Y, UNKNOWN, 0, 0);                     // Finish
            
            if (layers[i].type == "Double9") {
                add_instruction("POP", G, restore_idx, 0, 0);             // Delay
                add_instruction("HALT", 0, 0, G, cleanup_idx);            // Restore
            }
            
            layers[i-1].return_target = check_idx;
        }
    }
    
    // Fix Preamble
    int outer_layer_idx = layers.size() - 1;
    program[preamble_idx-1].b = layers[outer_layer_idx].val_in;
    program[preamble_idx-1].y = layers[outer_layer_idx].entry_instr;
    
    // Fix Return Targets
    for (int i = 0; i < layers.size(); ++i) {
        int target = (i == layers.size() - 1) ? final_halt_idx : layers[i+1].return_target;
        int instr_to_fix = -1;
        if (layers[i].type == "Base") {
            instr_to_fix = layers[i].entry_instr;
            program[instr_to_fix-1].x = target;
        } else if (layers[i].type == "Linear") {
            instr_to_fix = layers[i].entry_instr + 1;
            program[instr_to_fix-1].x = target;
        } else {
            instr_to_fix = layers[i].entry_instr + 5;
            program[instr_to_fix-1].x = target;
        }
    }

    cout << program.size() << "\n";
    for (const auto& instr : program) {
        if (instr.type == "HALT") {
            cout << "HALT PUSH " << instr.b << " GOTO " << instr.y << "\n";
        } else {
            cout << "POP " << instr.a << " GOTO " << instr.x << " PUSH " << instr.b << " GOTO " << instr.y << "\n";
        }
    }

    return 0;
}