| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include <bits/stdc++.h> |
| using namespace std; |
|
|
| constexpr long long P = 998244353; |
|
|
| int n_instr; |
| int maxChar; |
| int type_arr[30]; |
| int pop_char_arr[30], goto1_arr[30], push_char_arr[30], goto2_arr[30]; |
|
|
| |
| optional<pair<int, long long>> dp[30][1030]; |
| bool vis[30][1030]; |
| bool infinite_flag; |
|
|
| pair<int, long long> solve(int i, int x) { |
| if (dp[i][x]) return dp[i][x].value(); |
| if (vis[i][x]) { infinite_flag = true; return {-1, 0}; } |
| vis[i][x] = true; |
|
|
| if (type_arr[i] == 0) { |
| if (x == pop_char_arr[i]) { |
| dp[i][x] = {goto1_arr[i], 1LL}; |
| } else { |
| auto [j, u] = solve(goto2_arr[i], push_char_arr[i]); |
| if (infinite_flag) return {-1, 0}; |
| auto [k, v] = solve(j, x); |
| if (infinite_flag) return {-1, 0}; |
| dp[i][x] = {k, (u + v + 1) % P}; |
| } |
| } else { |
| if (x == 0) { |
| dp[i][x] = {-1, 1LL}; |
| } else { |
| auto [j, u] = solve(goto2_arr[i], push_char_arr[i]); |
| if (infinite_flag) return {-1, 0}; |
| auto [k, v] = solve(j, x); |
| if (infinite_flag) return {-1, 0}; |
| dp[i][x] = {k, (u + v + 1) % P}; |
| } |
| } |
| return dp[i][x].value(); |
| } |
|
|
| long long evaluate() { |
| for (int i = 0; i < n_instr; i++) |
| for (int j = 0; j <= maxChar; j++) { |
| dp[i][j].reset(); |
| vis[i][j] = false; |
| } |
| infinite_flag = false; |
| auto [fi, steps] = solve(0, 0); |
| if (infinite_flag) return -1; |
| return steps; |
| } |
|
|
| int main(int argc, char* argv[]) { |
| if (argc < 4) { |
| fprintf(stderr, "Usage: %s <target> <n> <alpha>\n", argv[0]); |
| return 1; |
| } |
| long long target = atoll(argv[1]); |
| n_instr = atoi(argv[2]); |
| maxChar = atoi(argv[3]); |
|
|
| 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(); |
| }; |
|
|
| |
| int best_type[30], best_pop[30], best_g1[30], best_push[30], best_g2[30]; |
| bool found = false; |
| int restarts = 0; |
|
|
| while (elapsed_ms() < 120000 && !found) { |
| restarts++; |
| |
| for (int i = 0; i < n_instr; i++) { |
| if (i == n_instr - 1) type_arr[i] = 1; |
| else type_arr[i] = 0; |
|
|
| if (type_arr[i] == 0) { |
| pop_char_arr[i] = 1 + rng() % maxChar; |
| goto1_arr[i] = rng() % n_instr; |
| push_char_arr[i] = 1 + rng() % maxChar; |
| goto2_arr[i] = rng() % n_instr; |
| } else { |
| push_char_arr[i] = 1 + rng() % maxChar; |
| goto2_arr[i] = rng() % n_instr; |
| } |
| } |
|
|
| long long T = evaluate(); |
| if (T < 0) continue; |
| if (T == target) { |
| found = true; |
| memcpy(best_type, type_arr, sizeof(best_type)); |
| memcpy(best_pop, pop_char_arr, sizeof(best_pop)); |
| memcpy(best_g1, goto1_arr, sizeof(best_g1)); |
| memcpy(best_push, push_char_arr, sizeof(best_push)); |
| memcpy(best_g2, goto2_arr, sizeof(best_g2)); |
| break; |
| } |
|
|
| |
| for (int iter = 0; iter < 200000 && !found; iter++) { |
| |
| int sv_type[30], sv_pop[30], sv_g1[30], sv_push[30], sv_g2[30]; |
| memcpy(sv_type, type_arr, sizeof(sv_type)); |
| memcpy(sv_pop, pop_char_arr, sizeof(sv_pop)); |
| memcpy(sv_g1, goto1_arr, sizeof(sv_g1)); |
| memcpy(sv_push, push_char_arr, sizeof(sv_push)); |
| memcpy(sv_g2, goto2_arr, sizeof(sv_g2)); |
|
|
| |
| int i = rng() % n_instr; |
| int what = rng() % 6; |
| if (what == 0 && i < n_instr - 1) { |
| |
| |
| } |
| if (what == 1 && type_arr[i] == 0) push_char_arr[i] = 1 + rng() % maxChar; |
| else if (what == 2) goto2_arr[i] = rng() % n_instr; |
| else if (what == 3 && type_arr[i] == 0) goto1_arr[i] = rng() % n_instr; |
| else if (what == 4 && type_arr[i] == 0) pop_char_arr[i] = 1 + rng() % maxChar; |
| else if (what == 5) { |
| if (type_arr[i] == 0) push_char_arr[i] = 1 + rng() % maxChar; |
| else push_char_arr[i] = 1 + rng() % maxChar; |
| } |
|
|
| long long nT = evaluate(); |
| if (nT < 0) { |
| memcpy(type_arr, sv_type, sizeof(sv_type)); |
| memcpy(pop_char_arr, sv_pop, sizeof(sv_pop)); |
| memcpy(goto1_arr, sv_g1, sizeof(sv_g1)); |
| memcpy(push_char_arr, sv_push, sizeof(sv_push)); |
| memcpy(goto2_arr, sv_g2, sizeof(sv_g2)); |
| continue; |
| } |
|
|
| if (nT == target) { |
| found = true; |
| memcpy(best_type, type_arr, sizeof(best_type)); |
| memcpy(best_pop, pop_char_arr, sizeof(best_pop)); |
| memcpy(best_g1, goto1_arr, sizeof(best_g1)); |
| memcpy(best_push, push_char_arr, sizeof(best_push)); |
| memcpy(best_g2, goto2_arr, sizeof(best_g2)); |
| break; |
| } |
|
|
| long long nd = min((nT - target + P) % P, (target - nT + P) % P); |
| long long od = min((T - target + P) % P, (target - T + P) % P); |
|
|
| if (nd <= od) { |
| T = nT; |
| } else { |
| memcpy(type_arr, sv_type, sizeof(sv_type)); |
| memcpy(pop_char_arr, sv_pop, sizeof(sv_pop)); |
| memcpy(goto1_arr, sv_g1, sizeof(sv_g1)); |
| memcpy(push_char_arr, sv_push, sizeof(sv_push)); |
| memcpy(goto2_arr, sv_g2, sizeof(sv_g2)); |
| } |
| } |
|
|
| if (restarts % 50 == 0) { |
| fprintf(stderr, "restart=%d elapsed=%ldms\n", restarts, elapsed_ms()); |
| } |
| } |
|
|
| if (found) { |
| fprintf(stderr, "FOUND n=%d alpha=%d after %d restarts\n", n_instr, maxChar, restarts); |
| printf("%d\n", n_instr); |
| for (int i = 0; i < n_instr; i++) { |
| if (best_type[i] == 0) { |
| printf("POP %d GOTO %d PUSH %d GOTO %d\n", |
| best_pop[i], best_g1[i]+1, best_push[i], best_g2[i]+1); |
| } else { |
| printf("HALT PUSH %d GOTO %d\n", best_push[i], best_g2[i]+1); |
| } |
| } |
| } else { |
| fprintf(stderr, "NOT FOUND n=%d alpha=%d after %d restarts\n", n_instr, maxChar, restarts); |
| } |
|
|
| return 0; |
| } |
|
|