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

using namespace std;

typedef long long ll;

struct Instruction {
    string type;
    int a; // or b for halt/push
    int x; // or y for halt/push
    int b;
    int y;
};

vector<Instruction> program;

// Helper to add instruction to the list
void add_inst(string type, int a, int x, int b = 0, int y = 0) {
    Instruction inst;
    inst.type = type;
    inst.a = a;
    inst.x = x;
    inst.b = b;
    inst.y = y;
    program.push_back(inst);
}

int main() {
    // Fast I/O
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    ll k;
    if (!(cin >> k)) return 0;

    // For small k, use a simple linear chain construction.
    // The overhead of the complex loop solution is around 120 steps.
    if (k < 300) {
        if (k == 1) {
            cout << "1\nHALT PUSH 1 GOTO 1" << endl;
            return 0;
        }
        
        // Strategy for K:
        // 1. Push 1 (1 step)
        // 2. Loop (K-3)/2 times: Push 2, Pop 2 (2 steps each)
        // 3. Pop 1 (1 step)
        // 4. Halt (1 step)
        // Total steps = 1 + (K-3) + 1 + 1 = K.
        
        // Inst 1: Push 1
        // Since stack is initially empty, POP fails and PUSH 1 GOTO 2 executes.
        add_inst("POP", 1000, 2, 1, 2); 
        
        ll pairs = (k - 3) / 2;
        int next_addr = 2;
        for (int i = 0; i < pairs; ++i) {
            // Push 2: Top is 1, so POP 1000 fails -> Pushes 2
            add_inst("POP", 1000, next_addr + 1, 2, next_addr + 1);
            // Pop 2: Top is 2, so POP 2 succeeds -> Pops 2
            add_inst("POP", 2, next_addr + 2, 1, next_addr + 2); 
            next_addr += 2;
        }
        
        // Pop 1
        add_inst("POP", 1, next_addr + 1, 1, next_addr + 1);
        
        // Halt: Stack empty -> Halts.
        add_inst("HALT", 1, next_addr + 1, 0, 0); 
        
        cout << program.size() << endl;
        for (const auto& inst : program) {
            if (inst.type == "HALT") {
                cout << "HALT PUSH " << inst.a << " GOTO " << inst.x << endl;
            } else {
                cout << "POP " << inst.a << " GOTO " << inst.x << " PUSH " << inst.b << " GOTO " << inst.y << endl;
            }
        }
        return 0;
    }

    // For large K, use a loop-based solution simulating a counter.
    // We define a cost function G(v) representing steps to clear value v from stack.
    // G(v) ~= 2 * G(v-1), providing exponential growth.
    // M=30 gives G(30) > 2^31.
    int M = 30;
    vector<ll> G(M + 1);
    // Base cost for v=1: Dispatch Loop checks M..1. Check 1 succeeds.
    // Cost = (Checks M..2 failing) + (Check 1 success).
    // Failing check costs 2 steps. Success costs 1 step.
    // G(1) = 2*(M-1) + 1 = 2M - 1.
    G[1] = 2LL * M - 1;
    for (int v = 2; v <= M; ++v) {
        // G(v) = Dispatch(v) + Expansion + 2*G(v-1)
        // Dispatch(v): 2*(M-v) + 1
        // Expansion: Push v-1, Push v-1 => 2 steps
        // Total overhead for v > 1: 2M - 2v + 3
        G[v] = (2LL * M - 2LL * v + 3) + 2LL * G[v - 1];
    }
    
    // Total steps = BurnSteps + LoadSteps + Sum(G(u)) + LoopEmptyCheck + Halt
    // LoopEmptyCheck: Checks M..1 on empty stack, all fail => 2M steps.
    // Halt => 1 step.
    // Fixed overhead = 2M + 1.
    
    ll target = k - (2LL * M + 1);
    vector<int> u;
    
    // Greedy decomposition of Target
    while (true) {
        int best_v = -1;
        // Each load adds 1 step plus G[v] steps
        for (int v = M; v >= 1; --v) {
            if (G[v] + 1 <= target) {
                best_v = v;
                break;
            }
        }
        if (best_v == -1) break;
        
        u.push_back(best_v);
        target -= (G[best_v] + 1);
    }
    
    // Remaining target must be satisfied by "Burn" instructions.
    // Burn adds pairs of steps (Push X, Pop X).
    // Target parity check: K is odd, 2M+1 is odd => Initial target even.
    // G[v] is odd => G[v]+1 is even.
    // Subtracting even from even => target remains even.
    // So target is always non-negative even number here.
    ll burn_pairs = target / 2;
    
    // Code Generation
    
    // 1. Burn Instructions
    int current_line = 1;
    for (int i = 0; i < burn_pairs; ++i) {
        // Pair: Push 1000, Pop 1000.
        // Line A: POP 1000 (fails) -> Push 1000 -> Goto B
        // Line B: POP 1000 (succeeds) -> Goto Next
        add_inst("POP", 1000, current_line + 1, 1000, current_line + 1);
        add_inst("POP", 1000, current_line + 2, 1, current_line + 2);
        current_line += 2;
    }
    
    // 2. Load Instructions
    int load_count = u.size();
    int loop_start = current_line + load_count;
    
    for (int i = 0; i < load_count; ++i) {
        int val = u[i];
        int next_addr = (i == load_count - 1) ? loop_start : current_line + 1;
        // PUSH val: POP 1000 (fails) -> Push val -> Goto Next
        add_inst("POP", 1000, next_addr, val, next_addr);
        current_line++;
    }
    
    // 3. Loop Instructions
    // Address mapping
    struct BlockAddr {
        int check;
        int fail;
        int expand;
        int p2;
    };
    vector<BlockAddr> blocks(M + 1);
    int addr = loop_start;
    
    // Check_30 is the entry point
    blocks[M].check = addr;
    
    for (int v = M; v >= 2; --v) {
        blocks[v].check = addr;
        blocks[v].fail = addr + 1;
        blocks[v].expand = addr + 2;
        blocks[v].p2 = addr + 3;
        addr += 4;
    }
    
    blocks[1].check = addr;
    blocks[1].fail = addr + 1;
    addr += 2;
    
    int halt_addr = addr;
    
    // Generate loop code
    for (int v = M; v >= 2; --v) {
        // Check_v: If Top==v -> Expand_v; Else -> Fail_v (Push v)
        add_inst("POP", v, blocks[v].expand, v, blocks[v].fail);
        
        // Fail_v: Pop v (restore) -> Check_{v-1}
        int next_check = blocks[v-1].check;
        add_inst("POP", v, next_check, 1, next_check);
        
        // Expand_v: Push v-1 -> P2_v
        add_inst("POP", 1000, blocks[v].p2, v - 1, blocks[v].p2);
        
        // P2_v: Push v-1 -> Check_M (Loop start)
        add_inst("POP", 1000, blocks[M].check, v - 1, blocks[M].check);
    }
    
    // v = 1
    // Check_1: If Top==1 -> Loop start; Else -> Fail_1 (Push 1)
    add_inst("POP", 1, blocks[M].check, 1, blocks[1].fail);
    
    // Fail_1: Pop 1 -> Halt
    add_inst("POP", 1, halt_addr, 1, halt_addr);
    
    // Halt
    add_inst("HALT", 999, halt_addr, 0, 0);
    
    // Output
    cout << program.size() << endl;
    for (const auto& inst : program) {
        if (inst.type == "HALT") {
            cout << "HALT PUSH " << inst.a << " GOTO " << inst.x << endl;
        } else {
            cout << "POP " << inst.a << " GOTO " << inst.x << " PUSH " << inst.b << " GOTO " << inst.y << endl;
        }
    }

    return 0;
}