結果
| 問題 |
No.2398 ヒドラ崩し
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:09:19 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 11,142 bytes |
| コンパイル時間 | 1,309 ms |
| コンパイル使用メモリ | 122,796 KB |
| 実行使用メモリ | 51,968 KB |
| 最終ジャッジ日時 | 2025-05-14 13:10:30 |
| 合計ジャッジ時間 | 5,974 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | AC * 13 TLE * 1 -- * 17 |
ソースコード
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <functional> // Required for std::function
#include <vector>
using namespace std;
// Memoization map for computed Grundy values. Key is the Hydra string state.
map<string, int> memo;
// Memoization map for computed state strings h[n]. Key is pair {Hydra string state, n}.
map<pair<string, int>, string> state_cache;
// Heuristic limits to prevent excessive computation or memory usage.
// MAX_LEN: Maximum allowed string length for a Hydra state. States exceeding this are considered invalid/unreachable.
// This helps manage memory usage. 512MB memory limit suggests roughly 5*10^8 characters total storage.
// Initial string length up to 10^5. Strings can grow. MAX_LEN=200000 is a heuristic guess.
const int MAX_LEN = 200000;
// MAX_K: Limit for exploring states h[k] for k=1, 2, ..., MAX_K.
// A common heuristic in competitive programming for games with infinite moves.
const int MAX_K = 61;
// MAX_DEPTH: Limit for recursion depth to prevent stack overflow.
const int MAX_DEPTH = 1000;
// Current recursion depth counters
int current_depth_grundy = 0; // Depth counter for calculate_grundy function
int current_depth_state = 0; // Depth counter for get_state function
// Utility function to check if a string ends with "()"
bool ends_with_empty_paren(const string& s) {
// Check if string length is at least 2 and last two characters are "()"
return s.length() >= 2 && s.substr(s.length() - 2) == "()";
}
// Forward declarations for recursive functions
string get_state(string h, int n);
int calculate_grundy(string h);
/**
* @brief Computes the Hydra state string h[n] according to the problem rules.
*
* @param h The current Hydra string state.
* @param n The positive integer parameter for the move.
* @return string The resulting Hydra string state h[n]. Returns empty string if computation fails due to limits or invalid input.
*/
string get_state(string h, int n) {
// Base cases: empty hydra or invalid n
if (h.empty()) return "";
if (n <= 0) return "";
// Check cache for previously computed state h[n]
pair<string, int> cache_key = {h, n};
if (state_cache.count(cache_key)) {
return state_cache[cache_key];
}
// Check recursion depth limit for state generation
if (current_depth_state > MAX_DEPTH) return ""; // Return empty string indicating failure/limit
current_depth_state++; // Increment depth counter
string result = ""; // Stores the computed state string
// Apply the rules based on the structure of h:
// Case 1: h = h'()
// If h ends with "()", then h[n] = h'. The value of n doesn't matter.
if (ends_with_empty_paren(h)) {
result = h.substr(0, h.length() - 2);
} else {
// Case 2/3: h does not end with "()". It must be of the form h = h0 (h1).
string h0, h1;
int component_start = -1; // Start index of the last prime component (h1)
int balance = 0; // Parenthesis balance counter
// Scan from right to find the start of the last prime component
for (int k = h.length() - 1; k >= 0; --k) {
if (h[k] == ')') balance++;
else if (h[k] == '(') balance--;
if (balance == 0) { // Found the boundary where balance returns to 0
component_start = k;
break;
}
}
// Validate the structure found
if (component_start == -1) { // If balance never returns to 0 except at the beginning
// This means the entire string is wrapped like (....)
if (h[0] == '(' && h.back() == ')') { component_start = 0; } // Valid case: h=(...)
else { current_depth_state--; return ""; } // Error: Invalid structure
} else if(h[component_start] != '(') { // Component boundary must start with '(' for form (h1)
current_depth_state--; return ""; // Error: Invalid structure found
}
// Extract h0 and h1 from h = h0 + "(" + h1 + ")"
h0 = h.substr(0, component_start);
h1 = h.substr(component_start + 1, h.length() - component_start - 2);
// h1 must be a non-empty ("living") Hydra for Case 2/3 logic.
// If h1 is empty, it means the last component was "()", handled by Case 1.
if (h1.empty()) { current_depth_state--; return ""; } // Error state, should have been Case 1
// Subcases based on whether h1 ends with "()"
// Case 2a: h1 = h1'()
if (ends_with_empty_paren(h1)) {
string h1_prime = h1.substr(0, h1.length() - 2); // Get h1' by removing trailing "()"
string h1_prime_paren = "(" + h1_prime + ")"; // Construct string "(h1')"
if (n == 1) { // If n=1, h[1] = h0 (h1')
result = h0 + h1_prime_paren;
} else { // If n > 1, h[n] = h[n-1] (h1')
// Recursively compute h[n-1] first
string prev_state = get_state(h, n - 1);
// Check if the recursive call succeeded
if (prev_state == "") {
current_depth_state--; return ""; // Propagate failure
}
// Concatenate h[n-1] and (h1')
result = prev_state + h1_prime_paren;
}
} else { // Case 2b: h1 does not end with "()"
// h[n] = h0 (h1[n])
// Recursively compute h1[n] first
string h1_n_state = get_state(h1, n);
// Check if the recursive call succeeded
if (h1_n_state == "") {
current_depth_state--; return ""; // Propagate failure
}
// Concatenate h0 and (h1[n])
result = h0 + "(" + h1_n_state + ")";
}
}
// Check final computed state length against limit
if (result.length() > MAX_LEN) {
current_depth_state--; return ""; // Return empty string if state is too large
}
current_depth_state--; // Decrement depth counter before returning
// Cache the computed state if it's valid (not empty string representing error/limit).
// Allow caching empty string result if initial h was empty.
if (!result.empty() || h.empty()) {
state_cache[cache_key] = result;
}
return result;
}
/**
* @brief Computes the Grundy value (nim-value) for a given Hydra state string h.
* Uses recursion with memoization (dynamic programming).
*
* @param h The Hydra string state.
* @return int The Grundy value G(h). Returns 0 if computation fails due to limits.
*/
int calculate_grundy(string h) {
// Base case: empty Hydra is a terminal state with Grundy value 0.
if (h.empty()) {
return 0;
}
// Check memoization table for cached Grundy value
if (memo.count(h)) {
return memo[h];
}
// Check recursion depth limit for Grundy calculation
if (current_depth_grundy > MAX_DEPTH) return 0; // Return 0 (losing state) as fallback
current_depth_grundy++; // Increment depth counter
// Set to store Grundy values of reachable states
set<int> next_grundy_values;
// Determine reachable states based on the structure of h:
// Case 1: h = h'()
if (ends_with_empty_paren(h)) {
string h_prime = h.substr(0, h.length() - 2); // The only reachable state is h'
// Check string length before recursive call to avoid exceeding limits
if (h_prime.length() <= MAX_LEN) {
next_grundy_values.insert(calculate_grundy(h_prime));
}
} else { // Case 2/3: h = h0 (h1)
// Re-parse h to find h0 and h1. This could be optimized if parse results were passed.
string h0, h1;
int component_start = -1;
int balance = 0;
for (int k = h.length() - 1; k >= 0; --k) {
if (h[k] == ')') balance++;
else if (h[k] == '(') balance--;
if (balance == 0) {
component_start = k;
break;
}
}
// Validate structure
if (component_start == -1) {
if (h[0] == '(' && h.back() == ')') { component_start = 0; }
else { current_depth_grundy--; return 0; } // Error/placeholder G
} else if(h[component_start] != '(') {
current_depth_grundy--; return 0; // Error/placeholder G
}
h0 = h.substr(0, component_start);
h1 = h.substr(component_start + 1, h.length() - component_start - 2);
if (h1.empty()) { current_depth_grundy--; return 0; } // Error/placeholder G
// Explore reachable states by trying k = 1, 2, ..., MAX_K
// The logic applies similarly to Case 2a and 2b, based on how get_state(h, k) behaves.
for (int k = 1; k <= MAX_K; ++k) {
// Compute the state resulting from move k
string next_state = get_state(h, k);
// Check if state generation failed (due to limits/errors)
// The condition `!h.empty() && k > 0` ensures we distinguish actual empty state target from error indicator ""
if (next_state == "" && !h.empty() && k > 0) {
// Stop exploring if state generation fails
break;
}
// Recursively compute Grundy value of the reachable state
int gk = calculate_grundy(next_state);
next_grundy_values.insert(gk); // Add to set of reachable Grundy values
// Heuristic optimization: stop exploring k if the mex value seems stable.
// Compute current mex based on values found so far.
int current_mex = 0;
while (next_grundy_values.count(current_mex)) current_mex++;
// If we've explored k up to current_mex + 2 (and at least 5 steps), assume mex won't change.
if (k >= current_mex + 2 && k >= 5) break;
}
}
// Calculate the mex (Minimum Excluded value) of the set of reachable Grundy values.
// This is the Grundy value G(h).
int mex = 0;
while (next_grundy_values.count(mex)) {
mex++;
}
current_depth_grundy--; // Decrement depth counter before returning
// Store computed Grundy value in memoization table
return memo[h] = mex;
}
int main() {
// Use faster I/O operations
ios_base::sync_with_stdio(false);
cin.tie(NULL);
string H; // Input Hydra string
cin >> H;
// Reset recursion depth counters for the main calculation
current_depth_grundy = 0;
current_depth_state = 0;
// Calculate the Grundy value of the initial state H
int result = calculate_grundy(H);
// Determine the winner based on the Grundy value G(H)
// If G(H) > 0, the first player has a winning strategy.
// If G(H) = 0, the second player has a winning strategy.
if (result > 0) {
cout << 0 << endl; // First player (Hydra Lover Robot) wins
} else {
cout << 1 << endl; // Second player (Hydra Lover Robot Lover Robot) wins
}
return 0;
}
qwewe