| |
| |
| #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_instr; |
| int type_arr[30]; |
| int pop_char_arr[30], goto1_arr[30], push_char_arr[30], goto2_arr[30]; |
|
|
| int maxChar; |
| optional<pair<int, MInt>> dp[30][1030]; |
| bool vis[30][1030]; |
| 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_arr[i] == 0) { |
| if (x == pop_char_arr[i]) { |
| dp[i][x] = {goto1_arr[i], MInt(1)}; |
| } else { |
| auto [j, u] = solve(goto2_arr[i], push_char_arr[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_arr[i], push_char_arr[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_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 MInt(P - 1); |
| return steps; |
| } |
|
|
| int main() { |
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
|
|
| |
|
|
| n_instr = 3; |
| maxChar = 4; |
|
|
| set<long long> seen_steps; |
| long long max_steps = 0; |
|
|
| |
| |
| |
|
|
| int count = 0; |
| int halting = 0; |
|
|
| for (int t0 = 0; t0 <= 1; t0++) |
| for (int t1 = 0; t1 <= 1; t1++) { |
| type_arr[2] = 1; |
| type_arr[0] = t0; |
| type_arr[1] = t1; |
|
|
| auto enumerate_instr = [&](int i, auto& self, auto& callback) -> void { |
| if (i == n_instr) { |
| callback(); |
| return; |
| } |
| if (type_arr[i] == 0) { |
| for (int a = 1; a <= maxChar; a++) |
| for (int g1 = 0; g1 < n_instr; g1++) |
| for (int c = 1; c <= maxChar; c++) |
| for (int g2 = 0; g2 < n_instr; g2++) { |
| pop_char_arr[i] = a; |
| goto1_arr[i] = g1; |
| push_char_arr[i] = c; |
| goto2_arr[i] = g2; |
| self(i + 1, self, callback); |
| } |
| } else { |
| for (int c = 1; c <= maxChar; c++) |
| for (int g2 = 0; g2 < n_instr; g2++) { |
| push_char_arr[i] = c; |
| goto2_arr[i] = g2; |
| self(i + 1, self, callback); |
| } |
| } |
| }; |
|
|
| auto callback = [&]() { |
| count++; |
| MInt T = evaluate(); |
| if (T.x != (P - 1) % P) { |
| halting++; |
| seen_steps.insert(T.x); |
| if (T.x > max_steps) { |
| max_steps = T.x; |
| cerr << "New max: " << T.x << " with config:"; |
| for (int i = 0; i < n_instr; i++) { |
| if (type_arr[i] == 0) { |
| cerr << " POP" << pop_char_arr[i] << "→" << goto1_arr[i] << ",push" << push_char_arr[i] << "→" << goto2_arr[i]; |
| } else { |
| cerr << " HALT,push" << push_char_arr[i] << "→" << goto2_arr[i]; |
| } |
| } |
| cerr << endl; |
| } |
| } |
| }; |
|
|
| enumerate_instr(0, enumerate_instr, callback); |
| } |
|
|
| cout << "Total programs: " << count << ", halting: " << halting << endl; |
| cout << "Distinct step counts: " << seen_steps.size() << endl; |
| cout << "Max step count: " << max_steps << endl; |
| cout << "First 50 step counts:"; |
| int printed = 0; |
| for (long long v : seen_steps) { |
| if (printed++ >= 50) break; |
| cout << " " << v; |
| } |
| cout << endl; |
|
|
| return 0; |
| } |
|
|