| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| constexpr long long P = 998244353; |
|
|
| struct MInt { |
| long long x; |
| MInt(): x(0) {} |
| MInt(long long v): x(((v % P) + P) % P) {} |
| MInt operator+(const MInt& b) const { return MInt(x + b.x); } |
| MInt operator-(const MInt& b) const { return MInt(x - b.x); } |
| MInt operator*(const MInt& b) const { return MInt(x * b.x); } |
| bool operator==(const MInt& b) const { return x == b.x; } |
| }; |
|
|
| int n; |
| int type[30]; |
| int pop_char[30], goto1[30], push_char[30], goto2[30]; |
| |
|
|
| optional<pair<int, MInt>> dp[30][1025]; |
| bool vis[30][1025]; |
| bool infinite_flag; |
|
|
| pair<int, MInt> solve(int i, int x) { |
| if (dp[i][x]) return dp[i][x].value(); |
| if (vis[i][x]) { infinite_flag = true; return {-1, MInt(0)}; } |
| vis[i][x] = true; |
|
|
| if (type[i] == 0) { |
| if (x == pop_char[i]) { |
| dp[i][x] = {goto1[i], MInt(1)}; |
| } else { |
| auto [j, u] = solve(goto2[i], push_char[i]); |
| if (infinite_flag) return {-1, MInt(0)}; |
| auto [k, v] = solve(j, x); |
| if (infinite_flag) return {-1, MInt(0)}; |
| dp[i][x] = {k, u + v + MInt(1)}; |
| } |
| } else { |
| if (x == 0) { |
| dp[i][x] = {-1, MInt(1)}; |
| } else { |
| auto [j, u] = solve(goto2[i], push_char[i]); |
| if (infinite_flag) return {-1, MInt(0)}; |
| auto [k, v] = solve(j, x); |
| if (infinite_flag) return {-1, MInt(0)}; |
| dp[i][x] = {k, u + v + MInt(1)}; |
| } |
| } |
| return dp[i][x].value(); |
| } |
|
|
| MInt evaluate() { |
| for (int i = 0; i < n; i++) |
| for (int j = 0; j <= 1024; j++) { |
| dp[i][j].reset(); |
| vis[i][j] = false; |
| } |
| infinite_flag = false; |
| auto [fi, steps] = solve(0, 0); |
| if (infinite_flag) return MInt(-1); |
| return steps; |
| } |
|
|
| int main(int argc, char* argv[]) { |
| if (argc < 3) { |
| cerr << "Usage: " << argv[0] << " <target_mod_P> <n_instructions>" << endl; |
| return 1; |
| } |
| long long target = atoll(argv[1]); |
| n = atoi(argv[2]); |
| int maxAlpha = min(n + 1, 5); |
|
|
| mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); |
|
|
| auto startTime = chrono::steady_clock::now(); |
| auto elapsed_ms = [&]() { |
| return chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - startTime).count(); |
| }; |
|
|
| |
| auto randomize = [&]() { |
| for (int i = 0; i < n; i++) { |
| if (i == n - 1) { |
| |
| type[i] = 1; |
| } else { |
| type[i] = (rng() % 4 == 0) ? 1 : 0; |
| } |
| if (type[i] == 0) { |
| pop_char[i] = 1 + rng() % maxAlpha; |
| goto1[i] = rng() % n; |
| push_char[i] = 1 + rng() % maxAlpha; |
| goto2[i] = rng() % n; |
| } else { |
| push_char[i] = 1 + rng() % maxAlpha; |
| goto2[i] = rng() % n; |
| } |
| } |
| }; |
|
|
| |
| auto mutate = [&]() { |
| int i = rng() % n; |
| int what = rng() % 5; |
| if (what == 0 && i < n - 1) { |
| |
| type[i] = 1 - type[i]; |
| if (type[i] == 0) { |
| pop_char[i] = 1 + rng() % maxAlpha; |
| goto1[i] = rng() % n; |
| push_char[i] = 1 + rng() % maxAlpha; |
| goto2[i] = rng() % n; |
| } else { |
| push_char[i] = 1 + rng() % maxAlpha; |
| goto2[i] = rng() % n; |
| } |
| } else if (what == 1) { |
| if (type[i] == 0) push_char[i] = 1 + rng() % maxAlpha; |
| else push_char[i] = 1 + rng() % maxAlpha; |
| } else if (what == 2) { |
| goto2[i] = rng() % n; |
| } else if (what == 3 && type[i] == 0) { |
| goto1[i] = rng() % n; |
| } else { |
| if (type[i] == 0) pop_char[i] = 1 + rng() % maxAlpha; |
| } |
| }; |
|
|
| int restarts = 0; |
| bool found = false; |
|
|
| |
| int best_type[30], best_pop_char[30], best_goto1[30], best_push_char[30], best_goto2[30]; |
|
|
| while (elapsed_ms() < 120000 && !found) { |
| restarts++; |
| randomize(); |
| MInt T = evaluate(); |
| if (T.x == (long long)(-1 + P) % P) continue; |
|
|
| if (T.x == target) { found = true; break; } |
|
|
| for (int iter = 0; iter < 100000 && !found; iter++) { |
| |
| int sv_type[30], sv_pop[30], sv_g1[30], sv_push[30], sv_g2[30]; |
| memcpy(sv_type, type, sizeof(int)*n); |
| memcpy(sv_pop, pop_char, sizeof(int)*n); |
| memcpy(sv_g1, goto1, sizeof(int)*n); |
| memcpy(sv_push, push_char, sizeof(int)*n); |
| memcpy(sv_g2, goto2, sizeof(int)*n); |
|
|
| mutate(); |
| MInt nT = evaluate(); |
| if (nT.x == (long long)(-1 + P) % P) { |
| |
| memcpy(type, sv_type, sizeof(int)*n); |
| memcpy(pop_char, sv_pop, sizeof(int)*n); |
| memcpy(goto1, sv_g1, sizeof(int)*n); |
| memcpy(push_char, sv_push, sizeof(int)*n); |
| memcpy(goto2, sv_g2, sizeof(int)*n); |
| continue; |
| } |
|
|
| if (nT.x == target) { found = true; break; } |
|
|
| long long nd = min((nT.x - target + P) % P, (target - nT.x + P) % P); |
| long long od = min((T.x - target + P) % P, (target - T.x + P) % P); |
|
|
| if (nd <= od) { |
| T = nT; |
| } else { |
| |
| memcpy(type, sv_type, sizeof(int)*n); |
| memcpy(pop_char, sv_pop, sizeof(int)*n); |
| memcpy(goto1, sv_g1, sizeof(int)*n); |
| memcpy(push_char, sv_push, sizeof(int)*n); |
| memcpy(goto2, sv_g2, sizeof(int)*n); |
| } |
| } |
|
|
| if (restarts % 100 == 0) { |
| cerr << "restart=" << restarts << " elapsed=" << elapsed_ms() << "ms" << endl; |
| } |
| } |
|
|
| if (found) { |
| cerr << "FOUND n=" << n << " after " << restarts << " restarts" << endl; |
| |
| cout << n << endl; |
| for (int i = 0; i < n; i++) { |
| if (type[i] == 0) { |
| cout << "POP " << pop_char[i] << " GOTO " << (goto1[i]+1) |
| << " PUSH " << push_char[i] << " GOTO " << (goto2[i]+1) << endl; |
| } else { |
| cout << "HALT PUSH " << push_char[i] << " GOTO " << (goto2[i]+1) << endl; |
| } |
| } |
| } else { |
| cerr << "NOT FOUND n=" << n << " after " << restarts << " restarts" << endl; |
| } |
|
|
| return 0; |
| } |
|
|