| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| static const long long P = 998244353; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| long long evaluate(int n, const int* push_val, const int* push_goto, int halt_push, int halt_goto, int maxVal) { |
| int nstates = n * (maxVal + 1); |
| vector<int> dest(nstates, -2); |
| vector<long long> cost(nstates, 0); |
| vector<int8_t> state(nstates, 0); |
|
|
| |
| struct Frame { |
| int i, x; |
| int phase; |
| int j; |
| long long u; |
| }; |
| vector<Frame> stack; |
| stack.reserve(nstates); |
|
|
| auto idx = [&](int i, int x) { return i * (maxVal + 1) + x; }; |
|
|
| auto push_frame = [&](int i, int x) -> bool { |
| int id = idx(i, x); |
| if (state[id] == 2) return true; |
| if (state[id] == 1) return false; |
| state[id] = 1; |
| stack.push_back({i, x, 0, 0, 0}); |
| return true; |
| }; |
|
|
| |
| if (!push_frame(0, 0)) return -1; |
|
|
| while (!stack.empty()) { |
| Frame& f = stack.back(); |
| int id = idx(f.i, f.x); |
|
|
| if (f.i < n - 1) { |
| int pop_v = f.i + 1; |
| if (f.x == pop_v) { |
| dest[id] = f.i + 1; |
| cost[id] = 1; |
| state[id] = 2; |
| stack.pop_back(); |
| continue; |
| } |
| |
| if (f.phase == 0) { |
| |
| int sub_i = push_goto[f.i]; |
| int sub_x = push_val[f.i]; |
| int sub_id = idx(sub_i, sub_x); |
| if (state[sub_id] == 2) { |
| f.j = dest[sub_id]; |
| f.u = cost[sub_id]; |
| f.phase = 1; |
| |
| } else if (state[sub_id] == 1) { |
| return -1; |
| } else { |
| state[sub_id] = 1; |
| f.phase = 1; |
| stack.push_back({sub_i, sub_x, 0, 0, 0}); |
| continue; |
| } |
| } |
| if (f.phase == 1) { |
| int sub_i = push_goto[f.i]; |
| int sub_x = push_val[f.i]; |
| int sub_id = idx(sub_i, sub_x); |
| if (state[sub_id] != 2) return -1; |
| f.j = dest[sub_id]; |
| f.u = cost[sub_id]; |
| |
| if (f.j == -1) { |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| return -1; |
| } |
| int sub_id2 = idx(f.j, f.x); |
| if (state[sub_id2] == 2) { |
| dest[id] = dest[sub_id2]; |
| cost[id] = (f.u + cost[sub_id2] + 1) % P; |
| state[id] = 2; |
| stack.pop_back(); |
| continue; |
| } else if (state[sub_id2] == 1) { |
| return -1; |
| } else { |
| state[sub_id2] = 1; |
| f.phase = 2; |
| stack.push_back({f.j, f.x, 0, 0, 0}); |
| continue; |
| } |
| } |
| if (f.phase == 2) { |
| int sub_id2 = idx(f.j, f.x); |
| if (state[sub_id2] != 2) return -1; |
| dest[id] = dest[sub_id2]; |
| cost[id] = (f.u + cost[sub_id2] + 1) % P; |
| state[id] = 2; |
| stack.pop_back(); |
| continue; |
| } |
| } else { |
| if (f.x == 0) { |
| dest[id] = -1; |
| cost[id] = 1; |
| state[id] = 2; |
| stack.pop_back(); |
| continue; |
| } |
| |
| if (f.phase == 0) { |
| int sub_i = halt_goto; |
| int sub_x = halt_push; |
| int sub_id = idx(sub_i, sub_x); |
| if (state[sub_id] == 2) { |
| f.j = dest[sub_id]; |
| f.u = cost[sub_id]; |
| f.phase = 1; |
| } else if (state[sub_id] == 1) { |
| return -1; |
| } else { |
| state[sub_id] = 1; |
| f.phase = 1; |
| stack.push_back({sub_i, sub_x, 0, 0, 0}); |
| continue; |
| } |
| } |
| if (f.phase == 1) { |
| int sub_i = halt_goto; |
| int sub_x = halt_push; |
| int sub_id = idx(sub_i, sub_x); |
| if (state[sub_id] != 2) return -1; |
| f.j = dest[sub_id]; |
| f.u = cost[sub_id]; |
| if (f.j == -1) return -1; |
| int sub_id2 = idx(f.j, f.x); |
| if (state[sub_id2] == 2) { |
| dest[id] = dest[sub_id2]; |
| cost[id] = (f.u + cost[sub_id2] + 1) % P; |
| state[id] = 2; |
| stack.pop_back(); |
| continue; |
| } else if (state[sub_id2] == 1) { |
| return -1; |
| } else { |
| state[sub_id2] = 1; |
| f.phase = 2; |
| stack.push_back({f.j, f.x, 0, 0, 0}); |
| continue; |
| } |
| } |
| if (f.phase == 2) { |
| int sub_id2 = idx(f.j, f.x); |
| if (state[sub_id2] != 2) return -1; |
| dest[id] = dest[sub_id2]; |
| cost[id] = (f.u + cost[sub_id2] + 1) % P; |
| state[id] = 2; |
| stack.pop_back(); |
| continue; |
| } |
| } |
| } |
|
|
| int id0 = idx(0, 0); |
| if (state[id0] != 2) return -1; |
| return cost[id0]; |
| } |
|
|
| int main() { |
| long long targets[2] = {150994941LL, 150994939LL}; |
|
|
| |
| |
| |
| |
|
|
| for (int n = 5; n <= 20; n++) { |
| int d = n - 1; |
| int V = min(d, 5); |
|
|
| cerr << "n=" << n << " V=" << V << endl; |
|
|
| mt19937 rng(42 + n * 999979); |
| bool found[2] = {false, false}; |
|
|
| auto startTime = chrono::steady_clock::now(); |
| int timeLimit = 10000; |
|
|
| int push_val[25], push_goto[25]; |
| int halt_push, halt_goto; |
| int best_push_val[2][25], best_push_goto[2][25], best_halt_push[2], best_halt_goto[2]; |
|
|
| long long attempts = 0; |
|
|
| while (!(found[0] && found[1])) { |
| auto now = chrono::steady_clock::now(); |
| auto ms = chrono::duration_cast<chrono::milliseconds>(now - startTime).count(); |
| if (ms > timeLimit) break; |
|
|
| |
| for (int i = 0; i < d; i++) { |
| push_val[i] = 1 + rng() % V; |
| push_goto[i] = rng() % n; |
| } |
| halt_push = 1 + rng() % V; |
| halt_goto = rng() % d; |
|
|
| long long cost = evaluate(n, push_val, push_goto, halt_push, halt_goto, V); |
| if (cost < 0) continue; |
|
|
| |
| for (int iter = 0; iter < 20000; iter++) { |
| for (int ti = 0; ti < 2; ti++) { |
| if (!found[ti] && cost == targets[ti]) { |
| found[ti] = true; |
| memcpy(best_push_val[ti], push_val, sizeof(int) * d); |
| memcpy(best_push_goto[ti], push_goto, sizeof(int) * d); |
| best_halt_push[ti] = halt_push; |
| best_halt_goto[ti] = halt_goto; |
| cerr << "FOUND n=" << n << " target" << (ti+1) << endl; |
| } |
| } |
| if (found[0] && found[1]) break; |
|
|
| |
| int save_val, save_goto, save_idx; |
| int mut_type = rng() % 3; |
| if (mut_type == 0) { |
| save_idx = rng() % d; |
| save_val = push_val[save_idx]; |
| push_val[save_idx] = 1 + rng() % V; |
| } else if (mut_type == 1) { |
| save_idx = rng() % d; |
| save_goto = push_goto[save_idx]; |
| push_goto[save_idx] = rng() % n; |
| } else { |
| save_val = halt_push; |
| save_goto = halt_goto; |
| halt_push = 1 + rng() % V; |
| halt_goto = rng() % d; |
| } |
|
|
| long long new_cost = evaluate(n, push_val, push_goto, halt_push, halt_goto, V); |
|
|
| bool accept = false; |
| if (new_cost >= 0) { |
| |
| long long bestOld = P, bestNew = P; |
| for (int ti = 0; ti < 2; ti++) { |
| if (!found[ti]) { |
| bestOld = min(bestOld, min((cost - targets[ti] + P) % P, (targets[ti] - cost + P) % P)); |
| bestNew = min(bestNew, min((new_cost - targets[ti] + P) % P, (targets[ti] - new_cost + P) % P)); |
| } |
| } |
| if (bestNew <= bestOld) accept = true; |
| } |
|
|
| if (accept) { |
| cost = new_cost; |
| } else { |
| |
| if (mut_type == 0) push_val[save_idx] = save_val; |
| else if (mut_type == 1) push_goto[save_idx] = save_goto; |
| else { halt_push = save_val; halt_goto = save_goto; } |
| } |
|
|
| attempts++; |
| } |
| } |
|
|
| auto ms = chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - startTime).count(); |
| cerr << " attempts=" << attempts << " time=" << ms << "ms found=" << found[0] << "," << found[1] << endl; |
|
|
| if (found[0] && found[1]) { |
| for (int ti = 0; ti < 2; ti++) { |
| cout << "Target " << (ti+1) << " (n=" << n << "):" << endl; |
| cout << n << endl; |
| for (int i = 0; i < d; i++) { |
| cout << "POP " << (i+1) << " GOTO " << (i+2) |
| << " PUSH " << best_push_val[ti][i] << " GOTO " << (best_push_goto[ti][i]+1) << endl; |
| } |
| cout << "HALT PUSH " << best_halt_push[ti] << " GOTO " << (best_halt_goto[ti]+1) << endl; |
| } |
| break; |
| } |
| } |
|
|
| return 0; |
| } |
|
|