#include using namespace std; static const long long P = 998244353; // Generalized chain: n-1 POP instructions + 1 HALT // POP instruction i: POP (i+1) GOTO pop_goto[i] PUSH push_val[i] GOTO push_goto[i] // HALT instruction (n-1): HALT PUSH halt_push GOTO halt_goto // // The standard chain has pop_goto[i]=i+1, push_val[i]=i+1, push_goto[i] varies // Let's generalize by allowing push_val and push_goto to vary more // For the checker DP, we need to simulate it properly // State: (instr, top_of_stack_value) struct Evaluator { int n; // POP instructions 0..n-2 vector pop_val; // = i+1 always vector pop_goto; // where to go when matched vector push_val; // what to push vector push_goto; // where to go when not matched // HALT instruction n-1 int halt_push; int halt_goto; // DP vector> dp_dest; vector> dp_cost; vector> dp_state; // 0=unvisited, 1=in-progress, 2=done bool has_cycle; void init() { dp_dest.assign(n, array{}); dp_cost.assign(n, array{}); dp_state.assign(n, array{}); has_cycle = false; } pair solve(int i, int x) { if (has_cycle) return {-2, 0}; if (dp_state[i][x] == 2) return {dp_dest[i][x], dp_cost[i][x]}; if (dp_state[i][x] == 1) { has_cycle = true; return {-2, 0}; } dp_state[i][x] = 1; int dest; long long cost; if (i < n - 1) { // POP if (x == pop_val[i]) { dest = pop_goto[i]; cost = 1; } else { auto [j, u] = solve(push_goto[i], push_val[i]); if (has_cycle) return {-2, 0}; auto [k, v] = solve(j, x); if (has_cycle) return {-2, 0}; dest = k; cost = (u + v + 1) % P; } } else { // HALT if (x == 0) { dest = -1; cost = 1; } else { auto [j, u] = solve(halt_goto, halt_push); if (has_cycle) return {-2, 0}; auto [k, v] = solve(j, x); if (has_cycle) return {-2, 0}; dest = k; cost = (u + v + 1) % P; } } dp_state[i][x] = 2; dp_dest[i][x] = dest; dp_cost[i][x] = cost; return {dest, cost}; } }; int main() { long long targets[2] = {150994941LL, 150994939LL}; // For the chain structure, let's count distinct values with different push_val choices // Standard: push_val[i] = i+1, pop_goto[i] = i+1, and push_goto[i] varies // Generalized: also vary push_val[i] and pop_goto[i] // First, let's see how many distinct values we get for n=12 (11 POP + 1 HALT) // with the standard structure (just varying push_goto) // We already know: ~2^d = 2^11 = 2048 // Let's try n=12 with varying BOTH push_goto[i] AND push_val[i] // push_val[i] can be 1..maxV // This might give us many more distinct values // Actually, let me think about what push_val does. // When instruction i doesn't match (x != i+1), it pushes push_val[i] and goes to push_goto[i]. // The cost includes solve(push_goto[i], push_val[i]).second // Different push_val values lead to different sub-computations. // With push_val values from 1..V, we have V*n choices for (push_val, push_goto) at each instruction. // Let's test: for d=11 (n=12), with V=5, how many distinct T values? // That's (5*12)^11 configs for the generalized version... way too many. // But maybe even with 2 push values, we get much more diversity. // Let me try a different approach: use the chain structure but with generalized push_vals // and do hill climbing on both push_goto AND push_val. for (int n = 10; n <= 28; n++) { cerr << "n=" << n << endl; int d = n - 1; // number of POP instructions mt19937 rng(42 + n * 1000003); bool found[2] = {false, false}; int foundConfig[2][35][2]; // [target][instr][push_val, push_goto] auto startTime = chrono::steady_clock::now(); int timeLimit = (n <= 15) ? 15000 : (n <= 20) ? 8000 : 3000; for (int restart = 0; !(found[0] && found[1]); restart++) { auto now = chrono::steady_clock::now(); auto ms = chrono::duration_cast(now - startTime).count(); if (ms > timeLimit) break; // Random initial config // pop_val[i] = i+1, pop_goto[i] = i+1 (always next) // push_val[i] random from 1..min(i+3, 20) // push_goto[i] random from 0..n-1 // halt_push = 1, halt_goto = n-1 Evaluator ev; ev.n = n; ev.pop_val.resize(d); ev.pop_goto.resize(d); ev.push_val.resize(d); ev.push_goto.resize(d); for (int i = 0; i < d; i++) { ev.pop_val[i] = i + 1; ev.pop_goto[i] = i + 1; // standard: next instruction int maxPV = min(i + 2, 10); // push values up to 10 ev.push_val[i] = 1 + rng() % maxPV; ev.push_goto[i] = rng() % n; } ev.halt_push = 1; ev.halt_goto = d; // self-loop at HALT... this might cause cycles // Actually, halt_goto pointing to itself with push causes cycle // Let halt_goto point to a POP instruction instead ev.halt_goto = rng() % d; // point to some POP instruction ev.init(); auto [dest, cost] = ev.solve(0, 0); if (ev.has_cycle) continue; // Hill climbing for (int iter = 0; iter < 50000; iter++) { for (int ti = 0; ti < 2; ti++) { if (!found[ti] && cost == targets[ti]) { found[ti] = true; cerr << "FOUND n=" << n << " target" << (ti+1) << " cost=" << cost << endl; // Print program cout << "FOUND n=" << n << " target" << (ti+1) << ":" << endl; cout << n << endl; for (int i = 0; i < d; i++) { cout << "POP " << ev.pop_val[i] << " GOTO " << (ev.pop_goto[i]+1) << " PUSH " << ev.push_val[i] << " GOTO " << (ev.push_goto[i]+1) << endl; } cout << "HALT PUSH " << ev.halt_push << " GOTO " << (ev.halt_goto+1) << endl; } } if (found[0] && found[1]) break; // Mutate: change one push_val or push_goto int choice = rng() % (2 * d + 2); // 2*d for POP params + 2 for HALT params Evaluator ev2 = ev; // shallow copy the config (not DP) // Apply mutation if (choice < d) { // Change push_val[choice] int maxPV = min(choice + 2, 10); ev2.push_val[choice] = 1 + rng() % maxPV; } else if (choice < 2*d) { // Change push_goto[choice - d] ev2.push_goto[choice - d] = rng() % n; } else if (choice == 2*d) { // Change halt_push ev2.halt_push = 1 + rng() % 10; } else { // Change halt_goto ev2.halt_goto = rng() % d; } ev2.init(); auto [dest2, cost2] = ev2.solve(0, 0); if (ev2.has_cycle) continue; // Accept if closer to either target long long bestDist = P; for (int ti = 0; ti < 2; ti++) { if (!found[ti]) { long long dd = min((cost - targets[ti] + P) % P, (targets[ti] - cost + P) % P); bestDist = min(bestDist, dd); } } long long newBestDist = P; for (int ti = 0; ti < 2; ti++) { if (!found[ti]) { long long dd = min((cost2 - targets[ti] + P) % P, (targets[ti] - cost2 + P) % P); newBestDist = min(newBestDist, dd); } } if (newBestDist <= bestDist) { ev.push_val = ev2.push_val; ev.push_goto = ev2.push_goto; ev.halt_push = ev2.halt_push; ev.halt_goto = ev2.halt_goto; cost = cost2; } } } cerr << " found=" << found[0] << "," << found[1] << endl; if (found[0] && found[1]) break; } return 0; }