提出 #65959793


ソースコード 拡げる

#include <iostream>
#include <vector>
#include <string>
#include <numeric>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <chrono> // For Timer and random seed
#include <functional> // For std::function for initializers
#include <array> // For fixed-size arrays M=12
#include <limits> // For std::numeric_limits
#include <random> // For std::mt19937 as an alternative RNG, though custom Xorshift is used

// Timer for managing time limits
class Timer {
public:
    Timer() : start_time_(std::chrono::high_resolution_clock::now()) {}

    void reset() {
        start_time_ = std::chrono::high_resolution_clock::now();
    }

    double get_elapsed_seconds() const {
        auto now = std::chrono::high_resolution_clock::now();
        return std::chrono::duration<double>(now - start_time_).count();
    }

private:
    std::chrono::time_point<std::chrono::high_resolution_clock> start_time_;
};

// Problem Constraints are fixed
constexpr int N_FIXED = 36; 
constexpr int M_FIXED = 12; 
constexpr int MAX_S_LEN_FIXED = 12; 
constexpr int CHAR_COUNT = 6; // 'a' through 'f'

// SA Parameters
constexpr int K_POWER_STATIONARY_DIST = 32; // MODIFIED from 64
constexpr int INITIAL_MAX_DELTA_A_TRANSFER = 20; // Max % to transfer in one A_ij move initially

// New constants for improved moves & strategy
constexpr double Q_K_EPSILON = 1e-9; // MODIFIED from 1e-6
constexpr int INITIAL_STRING_FOCUS_MAX_DELTA = 10; // New constant for adaptive string focus delta
constexpr int ENHANCED_C_NUM_PREDECESSORS_TO_UPDATE = 3; // How many predecessors to update after a C_k change
constexpr int STRING_FOCUS_W_CANDIDATES = 3; // How many low/high utility transitions to consider for smart moves

// Precomputed data structure
struct GlobalPrecomputedData {
    // string_char_pairs_locations[c1-'a'][c2-'a'] stores {string_index, char_start_pos_in_that_string}
    std::array<std::array<std::vector<std::pair<int, int>>, CHAR_COUNT>, CHAR_COUNT> string_char_pairs_locations;

    void precompute(const std::array<std::string, N_FIXED>& S_arr) {
        for (int c1 = 0; c1 < CHAR_COUNT; ++c1) {
            for (int c2 = 0; c2 < CHAR_COUNT; ++c2) {
                string_char_pairs_locations[c1][c2].clear();
            }
        }

        for (int k_idx = 0; k_idx < N_FIXED; ++k_idx) {
            const auto& Sk = S_arr[k_idx];
            if (Sk.length() < 2) continue;
            for (size_t char_idx = 0; char_idx < Sk.length() - 1; ++char_idx) {
                char ch1 = Sk[char_idx];
                char ch2 = Sk[char_idx+1];
                // Ensure characters are within 'a' to 'f'
                if (ch1 >= 'a' && ch1 < ('a' + CHAR_COUNT) && ch2 >= 'a' && ch2 < ('a' + CHAR_COUNT)) {
                    string_char_pairs_locations[ch1-'a'][ch2-'a'].emplace_back(k_idx, static_cast<int>(char_idx));
                }
            }
        }
    }
};


// Structure to hold problem input
struct ProblemInput {
    std::array<std::string, N_FIXED> S;
    std::array<int, N_FIXED> P;
    int N_read, M_read; // Actual N, M from input (though fixed for this problem)
    double L;     // Length of generated string (using double for 10^6 to match type in ScoreCalculator)

    void read() {
        std::cin >> N_read >> M_read >> L; 
        for (int i = 0; i < N_FIXED; ++i) {
            std::cin >> S[i] >> P[i];
        }
    }
};

// Solution structure
struct Solution {
    std::array<char, M_FIXED> C; 
    std::array<std::array<int, M_FIXED>, M_FIXED> A;

    Solution() { 
        if (M_FIXED > 0) { // Default constructor: uniform A, 'a' for C
            for (int i = 0; i < M_FIXED; ++i) {
                C[i] = 'a'; 
                if (M_FIXED == 0) continue; // Should not happen if M_FIXED > 0 check passes
                int base_prob = 100 / M_FIXED;
                int remainder = 100 % M_FIXED;
                for(int j_col=0; j_col < M_FIXED; ++j_col) A[i][j_col] = base_prob;
                for(int j_col=0; j_col < remainder; ++j_col) A[i][j_col]++;
            }
        }
    }

    void print() const {
        std::cout << std::fixed << std::setprecision(0); // Ensure integers are printed as integers
        for (int i = 0; i < M_FIXED; ++i) {
            std::cout << C[i];
            for (int j = 0; j < M_FIXED; ++j) {
                std::cout << " " << A[i][j];
            }
            std::cout << std::endl;
        }
    }
};

// Basic Xorshift RNG
struct Random {
    unsigned int x, y, z, w;
    Random(unsigned int seed) : x(seed), y(362436069), z(521288629), w(88675123) {
        if (seed == 0) x = 123456789; // Ensure x is not 0 if seed is 0
        if (y == 0) y = 362436069; // Default non-zero if somehow initialized to 0
        if (z == 0) z = 521288629;
        if (w == 0) w = 88675123;
    }
    using result_type = unsigned int;
    static constexpr result_type min() { return 0; }
    static constexpr result_type max() { return std::numeric_limits<unsigned int>::max(); }
    
    unsigned int next_int_internal() { 
        unsigned int t = x ^ (x << 11);
        x = y; y = z; z = w;
        w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
        return w;
    }
    result_type operator()() { return next_int_internal(); }
    double next_double() { // Returns [0.0, 1.0)
        return static_cast<double>(next_int_internal()) / (static_cast<double>(max()) + 1.0); 
    }
    int next_int_range(int min_val, int max_val) { // Returns [min_val, max_val]
        if (min_val > max_val) return min_val; // Or throw error, but for CP, this is safer
        return min_val + next_int_internal() % (max_val - min_val + 1);
    }
};

// M_FIXED x M_FIXED matrix of doubles
using MatrixM_Double = std::array<std::array<double, M_FIXED>, M_FIXED>;

MatrixM_Double multiply_matrices(const MatrixM_Double& A_mat, const MatrixM_Double& B_mat) {
    MatrixM_Double C_mat{}; // Value-initialize to zeros
    if (M_FIXED == 0) return C_mat;
    for (int i = 0; i < M_FIXED; ++i) {
        for (int j = 0; j < M_FIXED; ++j) {
            double sum = 0.0;
            for (int l = 0; l < M_FIXED; ++l) {
                sum += A_mat[i][l] * B_mat[l][j];
            }
            C_mat[i][j] = sum;
        }
    }
    return C_mat;
}

MatrixM_Double matrix_pow(MatrixM_Double base_matrix, int power) {
    MatrixM_Double res{}; // Value-initialize to zeros
    if (M_FIXED == 0) return res;
    for (int i = 0; i < M_FIXED; ++i) res[i][i] = 1.0; // Identity matrix

    while (power > 0) {
        if (power % 2 == 1) res = multiply_matrices(res, base_matrix);
        base_matrix = multiply_matrices(base_matrix, base_matrix);
        power /= 2;
    }
    return res;
}

class ScoreCalculator {
public:
    const ProblemInput& input_ref; 
    // Cached members to avoid reallocations or repeated calculations within one score call
    std::array<double, M_FIXED> pi_dist_cached; 
    MatrixM_Double A_double_cached; 
    // p_sk_dp[char_idx_in_sk][state_idx] = prob of S_k[0...char_idx_in_sk] ending in state_idx
    std::array<std::array<double, M_FIXED>, MAX_S_LEN_FIXED> p_sk_dp; 

    ScoreCalculator(const ProblemInput& prob_input) : input_ref(prob_input) {}

    std::pair<double, std::array<double, N_FIXED>> calculate_score_with_Qk(const Solution& sol) {
        if (M_FIXED == 0) return {0.0, {}}; // Or handle as per problem for M=0

        // Convert A (int percentages) to A_double_cached (double probabilities)
        for (int i = 0; i < M_FIXED; ++i) {
            for (int j = 0; j < M_FIXED; ++j) {
                A_double_cached[i][j] = sol.A[i][j] / 100.0;
            }
        }
        
        // Approximate stationary distribution pi_dist_cached from state 0
        MatrixM_Double A_pow_K = matrix_pow(A_double_cached, K_POWER_STATIONARY_DIST);
        for (int j = 0; j < M_FIXED; ++j) {
            pi_dist_cached[j] = A_pow_K[0][j]; // Probability of being in state j after K steps, starting from state 0
        }
        
        // Normalize pi_dist_cached (should sum to 1 ideally, but float precision)
        double sum_pi_val = 0.0;
        for(int j=0; j < M_FIXED; ++j) sum_pi_val += pi_dist_cached[j];
        
        if (sum_pi_val > 1e-9) { // Avoid division by zero if sum is tiny
            for (int j=0; j < M_FIXED; ++j) pi_dist_cached[j] /= sum_pi_val;
        } else { // If sum is effectively zero (e.g. state 0 is a sink with no escape or all paths die)
            std::fill(pi_dist_cached.begin(), pi_dist_cached.end(), 0.0);
            if (M_FIXED > 0) pi_dist_cached[0] = 1.0; // Fallback: assume always in state 0 (arbitrary, but needs a dist)
        }

        double total_expected_preference = 0;
        std::array<double, N_FIXED> Q_k_values; // To store Q_k for each S_k

        for (int k_idx = 0; k_idx < N_FIXED; ++k_idx) { 
            const std::string& Sk = input_ref.S[k_idx];
            int Sk_len = Sk.length();
            if (Sk_len == 0) {
                Q_k_values[k_idx] = 0.0;
                continue;
            }

            // DP to calculate P(Sk starts at a random position | stationary dist)
            // p_sk_dp[char_idx][state_u] = P(Sk[0...char_idx] is generated AND ends in state_u)
            for (int u = 0; u < M_FIXED; ++u) { // Base case for Sk[0]
                if (sol.C[u] == Sk[0]) {
                    p_sk_dp[0][u] = pi_dist_cached[u];
                } else {
                    p_sk_dp[0][u] = 0.0;
                }
            }

            for (int char_idx = 0; char_idx < Sk_len - 1; ++char_idx) { // DP transitions for Sk[1]...Sk[len-1]
                for (int v_next_state = 0; v_next_state < M_FIXED; ++v_next_state) {
                    p_sk_dp[char_idx+1][v_next_state] = 0.0; 
                    if (sol.C[v_next_state] == Sk[char_idx+1]) {
                        double sum_prev_paths = 0.0;
                        for (int u_curr_state = 0; u_curr_state < M_FIXED; ++u_curr_state) {
                            // P(Sk[0...char_idx] ends u_curr_state) * P(transition u_curr_state -> v_next_state)
                            sum_prev_paths += p_sk_dp[char_idx][u_curr_state] * A_double_cached[u_curr_state][v_next_state];
                        }
                        p_sk_dp[char_idx+1][v_next_state] = sum_prev_paths;
                    }
                }
            }

            double prob_Sk_starts_at_random_pos = 0; // Sum over all states for the last char of Sk
            for (int u = 0; u < M_FIXED; ++u) {
                prob_Sk_starts_at_random_pos += p_sk_dp[Sk_len-1][u];
            }

            // Using Poisson approximation for Q_k (prob S_k appears at least once)
            double lambda_k = input_ref.L * prob_Sk_starts_at_random_pos; // Expected occurrences
            double Q_k; 
            
            // Handle lambda_k extremes for stability and correctness
            if (prob_Sk_starts_at_random_pos < 1e-100 || lambda_k < 1e-9) { // Effectively zero probability
                 Q_k = lambda_k; // For small x, 1 - e^-x approx x
            } else if (lambda_k > 30) { // For large lambda_k, e^-lambda_k is effectively 0
                 Q_k = 1.0;
            } else {
                 Q_k = -std::expm1(-lambda_k); // Equivalent to 1.0 - std::exp(-lambda_k) but more accurate for small lambda_k
            }
            
            if (std::isnan(Q_k) || Q_k < 0) Q_k = 0.0; // Safety checks
            if (Q_k > 1.0) Q_k = 1.0;

            Q_k_values[k_idx] = Q_k;
            total_expected_preference += input_ref.P[k_idx] * Q_k;
        }
        return {total_expected_preference, Q_k_values};
    }
};


// Normalizes a row of A based on proportions W_row, ensuring sum is 100.
void normalize_row_A(std::array<int, M_FIXED>& A_row, const std::array<double, M_FIXED>& W_row_proportions, Random& rnd) {
    if (M_FIXED == 0) return;

    double sum_proportions = 0;
    for(double p : W_row_proportions) sum_proportions += p;

    if (sum_proportions < 1e-9) { // If all proportions are near zero, distribute uniformly
        int base_prob = 100 / M_FIXED;
        int remainder = 100 % M_FIXED;
        for (int j = 0; j < M_FIXED; ++j) A_row[j] = base_prob;
        for (int j = 0; j < remainder; ++j) A_row[j]++; 
        return;
    }

    std::vector<std::pair<double, int>> fractional_parts_vec(M_FIXED);
    int current_sum_A_int_parts = 0;
    for (int j = 0; j < M_FIXED; ++j) {
        double exact_val = 100.0 * W_row_proportions[j] / sum_proportions;
        A_row[j] = static_cast<int>(exact_val);
        // Add small random jitter to fractional part for tie-breaking
        fractional_parts_vec[j] = {exact_val - A_row[j] + rnd.next_double() * 1e-7, j}; 
        current_sum_A_int_parts += A_row[j];
    }

    int diff_to_distribute = 100 - current_sum_A_int_parts;
    
    // Distribute remainder based on fractional parts
    if (diff_to_distribute != 0) {
        if (diff_to_distribute > 0) { // Need to add
            std::sort(fractional_parts_vec.rbegin(), fractional_parts_vec.rend()); // Sort descending by fractional part
            for (int k = 0; k < diff_to_distribute; ++k) {
                bool distributed_one = false;
                // Try to distribute to states with largest fractional parts, respecting A[j] <= 100
                for(int attempt = 0; attempt < M_FIXED; ++attempt) { 
                    int target_j = fractional_parts_vec[(k + attempt) % M_FIXED].second; 
                    if (A_row[target_j] < 100) {
                        A_row[target_j]++;
                        distributed_one = true;
                        break;
                    }
                }
                if (!distributed_one && M_FIXED > 0) { /* All viable states are 100. Sum should be 100*M_FIXED. Error if still need to add. */ break; } 
            }
        } else { // Need to subtract (diff_to_distribute is negative)
            std::sort(fractional_parts_vec.begin(), fractional_parts_vec.end()); // Sort ascending by fractional part
            for (int k = 0; k < -diff_to_distribute; ++k) {
                bool distributed_one = false;
                 // Try to take from states with smallest fractional parts, respecting A[j] >= 0
                for(int attempt = 0; attempt < M_FIXED; ++attempt) {
                    int target_j = fractional_parts_vec[(k + attempt) % M_FIXED].second;
                    if (A_row[target_j] > 0) {
                        A_row[target_j]--;
                        distributed_one = true;
                        break;
                    }
                }
                if (!distributed_one && M_FIXED > 0) { /* All viable states are 0. Sum should be 0. Error if still need to subtract. */ break; } 
            }
        }
    }
    
    // Final pass to fix any sum discrepancy due to all states being 0 or 100, or float issues
    int current_sum_final = 0; 
    for(int val : A_row) current_sum_final += val;
    int final_diff = 100 - current_sum_final;

    if (final_diff != 0 && M_FIXED > 0) {
        std::vector<int> p_indices(M_FIXED);
        std::iota(p_indices.begin(), p_indices.end(), 0);
        for(size_t sh_i = 0; sh_i < p_indices.size(); ++sh_i) {
             if (p_indices.empty() || sh_i >= p_indices.size() -1 && sh_i != 0) break; // Avoid issue if size is 0 or 1
             std::swap(p_indices[sh_i], p_indices[rnd.next_int_range(sh_i, p_indices.size()-1)]);
        }


        if (final_diff > 0) { // Need to add more
            for (int k_adj = 0; k_adj < final_diff; ++k_adj) {
                bool success_inc = false;
                for (int idx_to_inc : p_indices) { // Iterate through shuffled indices
                    if (A_row[idx_to_inc] < 100) {
                        A_row[idx_to_inc]++;
                        success_inc = true;
                        break;
                    }
                }
                 // This fallback should ideally not be needed if logic above is perfect and M_FIXED > 0.
                if (!success_inc) { A_row[p_indices[rnd.next_int_range(0,M_FIXED-1)]]++; } 
            }
        } else { // Need to subtract more (final_diff < 0)
            for (int k_adj = 0; k_adj < -final_diff; ++k_adj) {
                bool success_dec = false;
                for (int idx_to_dec : p_indices) { // Iterate through shuffled indices
                    if (A_row[idx_to_dec] > 0) {
                        A_row[idx_to_dec]--;
                        success_dec = true;
                        break;
                    }
                }
                if (!success_dec ) { A_row[p_indices[rnd.next_int_range(0,M_FIXED-1)]]--; }
            }
        }
    }
}

// Updates row A[i_state] based on current Qk values and character assignments
void update_row_A_from_adaptive_heuristic(int i_state, Solution& sol_being_built, 
                                          const ProblemInput& input, Random& rnd, 
                                          const std::array<double, N_FIXED>& qk_values_of_current_eval,
                                          const GlobalPrecomputedData& precomputed) {
    if (M_FIXED == 0) return;
    std::array<double, M_FIXED> W_row; // Proportions for transitions from i_state
    std::fill(W_row.begin(), W_row.end(), 0.0);

    char Ci = sol_being_built.C[i_state];

    for (int j_next_state = 0; j_next_state < M_FIXED; ++j_next_state) {
        char Cj = sol_being_built.C[j_next_state];
        double sum_score_weights = 1e-9; // Start with a small epsilon to avoid all-zero weights

        // Check if characters are valid indices
        if (Ci >= 'a' && Ci < ('a' + CHAR_COUNT) && Cj >= 'a' && Cj < ('a' + CHAR_COUNT)) {
            const auto& relevant_pairs = precomputed.string_char_pairs_locations[Ci-'a'][Cj-'a'];
            for (const auto& p_info : relevant_pairs) {
                int k_idx = p_info.first; // String index
                // Weight by preference and how much Q_k can still improve (1 - Q_k)
                sum_score_weights += input.P[k_idx] * (1.0 - qk_values_of_current_eval[k_idx] + Q_K_EPSILON);
            }
        }
        W_row[j_next_state] = sum_score_weights;
    }
    normalize_row_A(sol_being_built.A[i_state], W_row, rnd);
}

enum class InitializerType { C_ONLY, C_AND_A };
struct InitializerMeta {
    InitializerType type;
    std::function<void(Solution&, Random&, const ProblemInput&, const GlobalPrecomputedData&)> func;
    std::string name; 
};


void solve(const ProblemInput& input, 
           const GlobalPrecomputedData& precomputed,
           Solution& best_sol_for_this_run, // Output: best solution found in this SA run
           double& best_score_for_this_run, // Output: its score
           std::array<double, N_FIXED>& best_Q_k_for_this_run, // Output: its Q_k values
           Random& rnd, 
           const Timer& /* run_timer_overall_progress */, // Unused directly, SA uses its own timer for this run
           double time_limit_for_this_sa_run,
           const InitializerMeta& initializer_meta
          ) 
{
    Solution current_sol; 
    ScoreCalculator score_calc(input);

    // Initialize solution (C and possibly A)
    if (initializer_meta.type == InitializerType::C_AND_A) {
        initializer_meta.func(current_sol, rnd, input, precomputed);
    } else { // C_ONLY
        initializer_meta.func(current_sol, rnd, input, precomputed); 
        // For C_ONLY initializers, A matrix needs to be initialized.
        // Use adaptive heuristic with dummy Q_k (all zeros, meaning all strings are equally "needed")
        std::array<double, N_FIXED> initial_dummy_qk; 
        std::fill(initial_dummy_qk.begin(), initial_dummy_qk.end(), 0.0); 
        for (int i = 0; i < M_FIXED; ++i) {
            update_row_A_from_adaptive_heuristic(i, current_sol, input, rnd, initial_dummy_qk, precomputed);
        }
    }
    
    auto score_and_qk = score_calc.calculate_score_with_Qk(current_sol);
    best_score_for_this_run = score_and_qk.first;
    best_sol_for_this_run = current_sol;
    best_Q_k_for_this_run = score_and_qk.second;

    double current_score_val = best_score_for_this_run;
    std::array<double, N_FIXED> current_Q_k_values = best_Q_k_for_this_run; 

    // SA temperature schedule
    double initial_temp_heuristic = std::abs(best_score_for_this_run);
    if (initial_temp_heuristic < 1.0 && initial_temp_heuristic >=0.0) {
        double sum_P = 0; for(int p_val : input.P) sum_P += p_val; // MODIFIED: Use sum_P
        initial_temp_heuristic = sum_P * 0.01; 
        if (initial_temp_heuristic < 1.0) initial_temp_heuristic = 1000.0;
    }
    else if (initial_temp_heuristic < 1.0) initial_temp_heuristic = 1000.0; // Handles negative scores


    double initial_temp = std::max(100.0, initial_temp_heuristic * 0.05); 
    if (initial_temp <= 1e-9) initial_temp = 1000.0; // Safety for zero/negative scores

    double final_temp = 0.1; 
    Timer sa_iteration_timer; // Timer for this specific SA run's duration

    while(true) {
        double elapsed_this_sa_run = sa_iteration_timer.get_elapsed_seconds();
        if (elapsed_this_sa_run >= time_limit_for_this_sa_run) break;
        
        // Progress for temperature annealing and move adaptation
        double progress = std::min(1.0, std::max(0.0, elapsed_this_sa_run / time_limit_for_this_sa_run)); 

        double temp_ratio_exponent = progress * progress; // Standard cooling schedule
        double temp = initial_temp * std::pow(final_temp / initial_temp, temp_ratio_exponent); 
        temp = std::max(final_temp, temp); // Ensure temp doesn't go below final_temp

        Solution next_sol = current_sol;
        
        double move_type_rand = rnd.next_double();
        
        // Define probabilities for different types of moves
        constexpr double PROB_C_CHANGE_SINGLE = 0.15;
        constexpr double PROB_C_SWAP_PAIR = 0.10; // New move: Swap C for two states
        constexpr double PROB_A_TRANSFER_PAIR = 0.40; // Transfer A[i][j1] <-> A[i][j2]
        constexpr double PROB_A_TRANSFER_SMART_SUBTYPE_RATIO = 0.55; 
        constexpr double PROB_RECOMPUTE_ROW_A = 0.15;
        // Remainder (0.20) for String-Focused A_ij Adjustment

        if (move_type_rand < PROB_C_CHANGE_SINGLE) { 
            if (M_FIXED == 0) continue;
            int k_state = rnd.next_int_range(0, M_FIXED - 1);
            char old_Ck = next_sol.C[k_state];
            char new_Ck = 'a' + rnd.next_int_range(0, CHAR_COUNT - 1); 
            if (new_Ck == old_Ck && CHAR_COUNT > 1) { // Ensure char actually changes if possible
                 new_Ck = 'a' + ( (old_Ck - 'a' + 1 + rnd.next_int_range(0, CHAR_COUNT - 2) ) % CHAR_COUNT );
            }
            if (CHAR_COUNT == 0) new_Ck = 'a'; // Safety
            else if (new_Ck < 'a' || new_Ck >= ('a' + CHAR_COUNT)) new_Ck = 'a'; // Safety for CHAR_COUNT=0 or bad range
            next_sol.C[k_state] = new_Ck;
            
            // Update outgoing transitions for k_state
            update_row_A_from_adaptive_heuristic(k_state, next_sol, input, rnd, current_Q_k_values, precomputed);

            // Update some important predecessors' outgoing transitions
            std::vector<int> predecessors_to_update;
            for (int i = 0; i < M_FIXED; ++i) {
                if (i == k_state) continue; 
                if (current_sol.A[i][k_state] > 20) { 
                     predecessors_to_update.push_back(i);
                }
            }
            if (!predecessors_to_update.empty()) {
                for(size_t sh_i = 0; sh_i < predecessors_to_update.size(); ++sh_i) {
                    if (predecessors_to_update.empty() || sh_i >= predecessors_to_update.size() -1 && sh_i != 0) break;
                    std::swap(predecessors_to_update[sh_i], predecessors_to_update[rnd.next_int_range(sh_i, predecessors_to_update.size()-1)]);
                }
                for(int count=0; count < std::min((int)predecessors_to_update.size(), ENHANCED_C_NUM_PREDECESSORS_TO_UPDATE); ++count) {
                    update_row_A_from_adaptive_heuristic(predecessors_to_update[count], next_sol, input, rnd, current_Q_k_values, precomputed);
                }
            }
        } else if (move_type_rand < PROB_C_CHANGE_SINGLE + PROB_C_SWAP_PAIR) { // C_SWAP_PAIR Move
            if (M_FIXED < 2) continue;
            int k1 = rnd.next_int_range(0, M_FIXED - 1);
            int k2 = rnd.next_int_range(0, M_FIXED - 1);
            if (k1 == k2) { // Ensure k1 and k2 are different
                if (M_FIXED > 1) k2 = (k1 + 1 + rnd.next_int_range(0, M_FIXED - 2)) % M_FIXED;
                else continue; // Should not happen if M_FIXED < 2 check passes
            }
            
            std::swap(next_sol.C[k1], next_sol.C[k2]);

            update_row_A_from_adaptive_heuristic(k1, next_sol, input, rnd, current_Q_k_values, precomputed);
            update_row_A_from_adaptive_heuristic(k2, next_sol, input, rnd, current_Q_k_values, precomputed);
            
            std::vector<int> predecessors_to_update;
            std::vector<bool> already_added(M_FIXED, false); 

            for (int i = 0; i < M_FIXED; ++i) {
                if (i == k1 || i == k2) continue;
                if (current_sol.A[i][k1] > 20 && !already_added[i]) { // Check against old k1 (now occupied by k2's char)
                     predecessors_to_update.push_back(i);
                     already_added[i] = true;
                }
                if (current_sol.A[i][k2] > 20 && !already_added[i]) { // Check against old k2 (now occupied by k1's char)
                     predecessors_to_update.push_back(i);
                     already_added[i] = true;
                }
            }
             if (!predecessors_to_update.empty()) {
                for(size_t sh_i = 0; sh_i < predecessors_to_update.size(); ++sh_i) {
                    if (predecessors_to_update.empty() || sh_i >= predecessors_to_update.size() -1 && sh_i != 0) break;
                    std::swap(predecessors_to_update[sh_i], predecessors_to_update[rnd.next_int_range(sh_i, predecessors_to_update.size()-1)]);
                }
                for(int count=0; count < std::min((int)predecessors_to_update.size(), ENHANCED_C_NUM_PREDECESSORS_TO_UPDATE); ++count) {
                    update_row_A_from_adaptive_heuristic(predecessors_to_update[count], next_sol, input, rnd, current_Q_k_values, precomputed);
                }
            }

        } else if (move_type_rand < PROB_C_CHANGE_SINGLE + PROB_C_SWAP_PAIR + PROB_A_TRANSFER_PAIR) { // A_TRANSFER_PAIR Move
            if (M_FIXED == 0) continue;
            if (M_FIXED < 2 && rnd.next_double() <= PROB_A_TRANSFER_SMART_SUBTYPE_RATIO ) { // Smart subtype needs M_FIXED >=2
                 continue;
            }


            int i_state = rnd.next_int_range(0, M_FIXED - 1);
            int j1 = -1, j2 = -1;

            bool is_smart_transfer_subtype = (M_FIXED >=2 && rnd.next_double() <= PROB_A_TRANSFER_SMART_SUBTYPE_RATIO);

            if (!is_smart_transfer_subtype) { 
                j1 = rnd.next_int_range(0, M_FIXED - 1);
                 if (M_FIXED > 1) {
                    j2 = rnd.next_int_range(0, M_FIXED - 1);
                    if (j1 == j2) j2 = (j1 + 1 + rnd.next_int_range(0, M_FIXED - 2)) % M_FIXED;
                } else { // M_FIXED == 1
                    j2 = j1; // No other choice, this move will be a no-op or fail delta constraint.
                }
            } else { // Smart transfer subtype (requires M_FIXED >= 2, ensured by is_smart_transfer_subtype condition)
                std::array<double, M_FIXED> W_row_smart; 
                char Ci_smart = next_sol.C[i_state];
                for (int j_idx = 0; j_idx < M_FIXED; ++j_idx) {
                    char Cj_smart = next_sol.C[j_idx];
                    double sum_score_weights = 1e-9; 
                    if (Ci_smart >= 'a' && Ci_smart < ('a'+CHAR_COUNT) && Cj_smart >= 'a' && Cj_smart < ('a'+CHAR_COUNT)) {
                        const auto& relevant_pairs = precomputed.string_char_pairs_locations[Ci_smart-'a'][Cj_smart-'a'];
                        for (const auto& p_info : relevant_pairs) {
                            int k_s_idx = p_info.first;
                            sum_score_weights += input.P[k_s_idx] * (1.0 - current_Q_k_values[k_s_idx] + Q_K_EPSILON);
                        }
                    }
                    W_row_smart[j_idx] = sum_score_weights;
                }
                
                std::vector<int> cand_j1, cand_j2_all; 
                for(int j=0; j < M_FIXED; ++j) {
                    if (next_sol.A[i_state][j] > 0) cand_j1.push_back(j); 
                    if (next_sol.A[i_state][j] < 100) cand_j2_all.push_back(j); 
                }

                if (cand_j1.empty() || cand_j2_all.empty()) continue; 

                std::sort(cand_j1.begin(), cand_j1.end(), [&](int a, int b){ return W_row_smart[a] < W_row_smart[b]; });
                int j1_max_idx = std::min((int)cand_j1.size() - 1, STRING_FOCUS_W_CANDIDATES -1); 
                if (j1_max_idx < 0) continue; 
                j1 = cand_j1[rnd.next_int_range(0, j1_max_idx)];
                
                std::vector<int> cand_j2; 
                for(int val : cand_j2_all) if(val != j1) cand_j2.push_back(val);
                if (cand_j2.empty()) continue;

                std::sort(cand_j2.begin(), cand_j2.end(), [&](int a, int b){ return W_row_smart[a] > W_row_smart[b]; });
                int j2_max_idx = std::min((int)cand_j2.size() - 1, STRING_FOCUS_W_CANDIDATES -1); 
                if (j2_max_idx < 0) continue;
                j2 = cand_j2[rnd.next_int_range(0, j2_max_idx)];
            }
            
            if (j1 == -1 || j2 == -1 || (j1 == j2 && M_FIXED > 1) ) continue; 
            if (j1 == j2 && M_FIXED == 1) { /* This is fine for M=1, delta will be 0 or move rejected */ }


            int current_max_delta_val = std::max(1, static_cast<int>(INITIAL_MAX_DELTA_A_TRANSFER * std::sqrt(1.0 - progress) + 0.5));
            // current_max_delta_val = std::max(1, current_max_delta_val); // already done by std::max(1, ...)

            int delta;
            bool transfer_j1_to_j2; 
            if(is_smart_transfer_subtype) { 
                transfer_j1_to_j2 = (rnd.next_double() < 0.75); 
            } else {
                transfer_j1_to_j2 = (rnd.next_double() < 0.5); 
            }
            
            if (j1 == j2) { // If only one state (M_FIXED=1) or bad luck in random choice for M_FIXED > 1 non-smart
                 continue; // No transfer possible
            }

            if (transfer_j1_to_j2) { 
                int max_d = std::min({current_max_delta_val, next_sol.A[i_state][j1], 100 - next_sol.A[i_state][j2]});
                if (max_d <= 0) continue;
                delta = rnd.next_int_range(1, max_d);
                next_sol.A[i_state][j1] -= delta;
                next_sol.A[i_state][j2] += delta;
            } else { 
                int max_d = std::min({current_max_delta_val, next_sol.A[i_state][j2], 100 - next_sol.A[i_state][j1]});
                if (max_d <= 0) continue;
                delta = rnd.next_int_range(1, max_d);
                next_sol.A[i_state][j2] -= delta;
                next_sol.A[i_state][j1] += delta;
            }

        } else if (move_type_rand < PROB_C_CHANGE_SINGLE + PROB_C_SWAP_PAIR + PROB_A_TRANSFER_PAIR + PROB_RECOMPUTE_ROW_A) { 
            if (M_FIXED == 0) continue;
            int i_state = rnd.next_int_range(0, M_FIXED - 1);
            update_row_A_from_adaptive_heuristic(i_state, next_sol, input, rnd, current_Q_k_values, precomputed);
        } else { // String-Focused A_ij Adjustment
            if (M_FIXED == 0 || N_FIXED == 0) continue;

            std::vector<double> string_weights(N_FIXED);
            double total_string_weight = 0;
            for (int k = 0; k < N_FIXED; ++k) {
                string_weights[k] = input.P[k] * (1.0 - current_Q_k_values[k] + Q_K_EPSILON);
                if (string_weights[k] < 0) string_weights[k] = Q_K_EPSILON * input.P[k]; 
                total_string_weight += string_weights[k];
            }

            if (total_string_weight < 1e-9) continue; 

            int k_idx_focus = N_FIXED -1; 
            double r_select_str = rnd.next_double() * total_string_weight;
            double cumulative_weight = 0;
            for (int k = 0; k < N_FIXED; ++k) {
                cumulative_weight += string_weights[k];
                if (r_select_str <= cumulative_weight) {
                    k_idx_focus = k;
                    break;
                }
            }
            
            const auto& Sk_focus = input.S[k_idx_focus];
            if (Sk_focus.length() < 2) continue; 

            int char_pair_start_idx = rnd.next_int_range(0, Sk_focus.length() - 2);
            char target_C1 = Sk_focus[char_pair_start_idx];
            char target_C2 = Sk_focus[char_pair_start_idx+1];

            std::vector<std::pair<int, int>> candidate_uv_pairs; 
            for (int u_s = 0; u_s < M_FIXED; ++u_s) {
                if (next_sol.C[u_s] == target_C1) {
                    for (int v_s = 0; v_s < M_FIXED; ++v_s) {
                        if (next_sol.C[v_s] == target_C2) {
                            candidate_uv_pairs.push_back({u_s, v_s});
                        }
                    }
                }
            }
            if (candidate_uv_pairs.empty()) continue; 
            std::pair<int,int> uv_to_boost = candidate_uv_pairs[rnd.next_int_range(0, candidate_uv_pairs.size()-1)];
            int u_focus = uv_to_boost.first;
            int v_focus = uv_to_boost.second;

            // MODIFIED: Adaptive delta for string focus move
            int current_max_delta_focus = std::max(1, static_cast<int>(INITIAL_STRING_FOCUS_MAX_DELTA * std::sqrt(1.0 - progress) + 0.5));
            // if (current_max_delta_focus <= 0) current_max_delta_focus = 1; // Already handled by std::max(1,...)

            int delta_s = rnd.next_int_range(1, current_max_delta_focus);
            delta_s = std::min(delta_s, 100 - next_sol.A[u_focus][v_focus]); 
            if (delta_s <= 0) continue; 

            std::vector<int> candidates_w_indices; 
            for (int w_s = 0; w_s < M_FIXED; ++w_s) {
                if (w_s != v_focus && next_sol.A[u_focus][w_s] >= delta_s) { 
                    candidates_w_indices.push_back(w_s);
                }
            }
            
            if (candidates_w_indices.empty()) { 
                int max_available_from_any_w = 0;
                 for (int w_s = 0; w_s < M_FIXED; ++w_s) {
                    if (w_s != v_focus) max_available_from_any_w = std::max(max_available_from_any_w, next_sol.A[u_focus][w_s]);
                }
                delta_s = std::min(delta_s, max_available_from_any_w); 
                if (delta_s <= 0) continue; 
                
                candidates_w_indices.clear(); 
                for (int w_s = 0; w_s < M_FIXED; ++w_s) { 
                    if (w_s != v_focus && next_sol.A[u_focus][w_s] >= delta_s) { // Use the new, possibly smaller delta_s
                         candidates_w_indices.push_back(w_s);
                    }
                }
                if (candidates_w_indices.empty()) continue; 
            }
            
            int w_focus = -1;
            std::vector<std::pair<double, int>> w_importances; 
            char Char_u_focus = next_sol.C[u_focus];

            for (int w_cand_idx : candidates_w_indices) {
                char Char_w_cand = next_sol.C[w_cand_idx];
                double importance_score = 1e-9; 
                 if (Char_u_focus >= 'a' && Char_u_focus < ('a'+CHAR_COUNT) && Char_w_cand >= 'a' && Char_w_cand < ('a'+CHAR_COUNT)) {
                    const auto& relevant_pairs = precomputed.string_char_pairs_locations[Char_u_focus-'a'][Char_w_cand-'a'];
                    for (const auto& p_info : relevant_pairs) {
                        int sk_idx = p_info.first;
                        importance_score += input.P[sk_idx] * (1.0 - current_Q_k_values[sk_idx] + Q_K_EPSILON);
                    }
                }
                w_importances.push_back({importance_score, w_cand_idx});
            }

            if (w_importances.empty()) continue;

            std::sort(w_importances.begin(), w_importances.end()); 
            
            int num_least_important_to_consider = std::min((int)w_importances.size(), STRING_FOCUS_W_CANDIDATES);
            if (num_least_important_to_consider == 0) continue; // Should be caught by w_importances.empty()
            w_focus = w_importances[rnd.next_int_range(0, num_least_important_to_consider - 1)].second;

            next_sol.A[u_focus][v_focus] += delta_s;
            next_sol.A[u_focus][w_focus] -= delta_s;
        }
        
        auto next_score_qk_pair = score_calc.calculate_score_with_Qk(next_sol);
        double next_score_eval = next_score_qk_pair.first;

        if (next_score_eval > current_score_val || (temp > 1e-9 && rnd.next_double() < std::exp((next_score_eval - current_score_val) / temp)) ) {
            current_sol = next_sol; 
            current_score_val = next_score_eval;
            current_Q_k_values = next_score_qk_pair.second;

            if (current_score_val > best_score_for_this_run) { 
                 best_score_for_this_run = current_score_val;
                 best_sol_for_this_run = current_sol;
                 best_Q_k_for_this_run = current_Q_k_values; 
            }
        }
    }
}

// Initializer Implementations
void C_init_weighted_random(Solution& sol, Random& rnd, const ProblemInput& input, const GlobalPrecomputedData& /*precomputed*/) {
    if (M_FIXED == 0) return;
    if (CHAR_COUNT == 0) { 
        for(int i=0; i<M_FIXED; ++i) sol.C[i] = 'a';
        return;
    }
    std::array<double, CHAR_COUNT> char_weights;
    std::fill(char_weights.begin(), char_weights.end(), 0.0);

    for(int i=0; i < N_FIXED; ++i) { 
        std::array<bool, CHAR_COUNT> char_seen_in_Sk{};
        for(char ch_in_Sk : input.S[i]) {
            if (ch_in_Sk >= 'a' && ch_in_Sk < ('a' + CHAR_COUNT)) {
                if (!char_seen_in_Sk[ch_in_Sk - 'a']) {
                     char_weights[ch_in_Sk - 'a'] += input.P[i];
                     char_seen_in_Sk[ch_in_Sk - 'a'] = true;
                }
            }
        }
    }

    double total_weight = 0;
    for(int i=0; i < CHAR_COUNT; ++i) {
        char_weights[i] += 1e-9; // Small epsilon to ensure non-zero weight if all P_i are zero for a char
        total_weight += char_weights[i];
    }
    if (total_weight < 1e-8 && CHAR_COUNT > 0) { // All P_i were zero or very small
         for(int i=0; i<CHAR_COUNT; ++i) char_weights[i] = 1.0/CHAR_COUNT; // Uniform
         total_weight = 1.0;
    }

    std::array<double, CHAR_COUNT> cumulative_probs;
    double current_cumulative = 0;
    for(int i=0; i < CHAR_COUNT; ++i) {
        if (total_weight > 1e-9) current_cumulative += char_weights[i] / total_weight;
        else if (CHAR_COUNT > 0) current_cumulative += 1.0 / CHAR_COUNT; // Fallback if total_weight is still zero
        cumulative_probs[i] = current_cumulative;
    }
    if (CHAR_COUNT > 0) cumulative_probs[CHAR_COUNT - 1] = 1.0000000001; // Ensure last bucket catches due to precision

    for (int i = 0; i < M_FIXED; ++i) { 
        double r_val = rnd.next_double();
        char assigned_char = (CHAR_COUNT > 0) ? ('a' + CHAR_COUNT - 1) : 'a'; // Default to last char if loop fails
        if (CHAR_COUNT > 0) { 
            for (int char_code = 0; char_code < CHAR_COUNT; ++char_code) {
                if (r_val < cumulative_probs[char_code]) {
                    assigned_char = 'a' + char_code;
                    break;
                }
            }
        }
        sol.C[i] = assigned_char;
    }
}

void C_and_A_init_greedy_string_cycle(Solution& sol, Random& rnd, const ProblemInput& input, const GlobalPrecomputedData& precomputed) {
    if (M_FIXED == 0) return;
    
    int best_s_idx = -1;
    int current_max_P = -1;
    int current_min_len_for_max_P = MAX_S_LEN_FIXED + 5; 
    std::string current_best_S_lex_for_max_P = "~"; // Lexicographically large sentinel

    for (int i = 0; i < N_FIXED; ++i) {
        if (input.S[i].empty()) continue;
        int current_S_len = static_cast<int>(input.S[i].length()); // Cast for comparison

        if (input.P[i] > current_max_P) {
            current_max_P = input.P[i];
            current_min_len_for_max_P = current_S_len;
            current_best_S_lex_for_max_P = input.S[i];
            best_s_idx = i;
        } else if (input.P[i] == current_max_P) {
            if (current_S_len < current_min_len_for_max_P) {
                current_min_len_for_max_P = current_S_len;
                current_best_S_lex_for_max_P = input.S[i];
                best_s_idx = i;
            } else if (current_S_len == current_min_len_for_max_P) {
                if (input.S[i] < current_best_S_lex_for_max_P) {
                    current_best_S_lex_for_max_P = input.S[i];
                    best_s_idx = i;
                }
            }
        }
    }
    
    std::array<double, N_FIXED> dummy_qk; 
    std::fill(dummy_qk.begin(), dummy_qk.end(), 0.0);

    if (best_s_idx != -1 && static_cast<int>(input.S[best_s_idx].length()) <= M_FIXED && !input.S[best_s_idx].empty()) {
        const std::string& S_star = input.S[best_s_idx];
        int s_star_len = S_star.length();
        // s_star_len > 0 is guaranteed by !input.S[best_s_idx].empty()
        
        C_init_weighted_random(sol, rnd, input, precomputed); // Initialize all C first

        for (int i = 0; i < s_star_len; ++i) {
            sol.C[i] = S_star[i]; // Overwrite C for cycle states
        }

        for (int i = 0; i < s_star_len; ++i) {
            // sol.A[i] will be set by normalize_row_A
            std::array<double, M_FIXED> W_temp; 
            std::fill(W_temp.begin(), W_temp.end(), 0.0);
            int next_state_in_cycle = (i + 1) % s_star_len;
            
            if (M_FIXED == 1 || s_star_len == M_FIXED) { 
                W_temp[next_state_in_cycle] = 100.0;
            } else { 
                W_temp[next_state_in_cycle] = 95.0;
                // Try to pick a random state for the remaining 5% that is NOT next_state_in_cycle
                int other_target_state_idx = rnd.next_int_range(0, M_FIXED - 1);
                if (other_target_state_idx == next_state_in_cycle) { // If same, pick another if possible
                    if (M_FIXED > 1) { // Need at least 2 states to pick a different one
                        other_target_state_idx = (next_state_in_cycle + 1 + rnd.next_int_range(0, M_FIXED - 2)) % M_FIXED;
                    } 
                    // If M_FIXED=1 or still same after retry (M_FIXED=2, unlucky), then it's fine, W_temp will handle it.
                }
                W_temp[other_target_state_idx] += 5.0; // Add to existing (0.0) or could sum if other_target is next_state_in_cycle
            }
            normalize_row_A(sol.A[i], W_temp, rnd);
        }

        // For states NOT in the S_star cycle (i.e., s_star_len to M_FIXED-1), initialize their A rows
        // Their C values are already set by C_init_weighted_random.
        for (int i = s_star_len; i < M_FIXED; ++i) { 
            update_row_A_from_adaptive_heuristic(i, sol, input, rnd, dummy_qk, precomputed);
        }

    } else { // Fallback if no good S_star or S_star too long
        C_init_weighted_random(sol, rnd, input, precomputed); 
        for (int i = 0; i < M_FIXED; ++i) { 
            update_row_A_from_adaptive_heuristic(i, sol, input, rnd, dummy_qk, precomputed);
        }
    }
}


void C_init_cyclic(Solution& sol, Random& /*rnd*/, const ProblemInput& /*input*/, const GlobalPrecomputedData& /*precomputed*/) {
    if (M_FIXED == 0 || CHAR_COUNT == 0) { 
        if (M_FIXED > 0 && CHAR_COUNT==0) for(int i=0; i<M_FIXED; ++i) sol.C[i] = 'a';
        return;
    }
    int states_per_char_bucket = std::max(1, M_FIXED / CHAR_COUNT); 
    for (int i = 0; i < M_FIXED; ++i) {
        sol.C[i] = 'a' + ((i / states_per_char_bucket) % CHAR_COUNT) ; 
    }
}

void C_init_random(Solution& sol, Random& rnd, const ProblemInput& /*input*/, const GlobalPrecomputedData& /*precomputed*/) {
    if (M_FIXED == 0 || CHAR_COUNT == 0) {
        if (M_FIXED > 0 && CHAR_COUNT==0) for(int i=0; i<M_FIXED; ++i) sol.C[i] = 'a';
        return;
    }
    for (int i = 0; i < M_FIXED; ++i) {
        sol.C[i] = 'a' + rnd.next_int_range(0, CHAR_COUNT - 1);
    }
}

void C_init_block(Solution& sol, Random& /*rnd*/, const ProblemInput& /*input*/, const GlobalPrecomputedData& /*precomputed*/) { 
    if (M_FIXED == 0 || CHAR_COUNT == 0) {
        if (M_FIXED > 0 && CHAR_COUNT==0) for(int i=0; i<M_FIXED; ++i) sol.C[i] = 'a';
        return;
    }
    for (int i = 0; i < M_FIXED; ++i) {
        sol.C[i] = 'a' + (i % CHAR_COUNT);
    }
}


int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);
    
    Timer overall_timer_main; 
    unsigned int base_seed = static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count());
    #ifdef ATCODER_DEBUG 
        // std::cerr << "DEBUG MODE: Using fixed seed." << std::endl;
        base_seed = 0xC0FFEE; // A fixed seed for local debugging
    #endif
    
    ProblemInput input_data;
    input_data.read();

    GlobalPrecomputedData global_precomputed;
    global_precomputed.precompute(input_data.S);

    Solution overall_best_sol; 
    double overall_max_score = -std::numeric_limits<double>::infinity(); 
    
    double total_time_limit_seconds = 1.98; // Slightly less than 2.0s for safety margin

    std::vector<InitializerMeta> initializers_meta;
    initializers_meta.push_back({InitializerType::C_AND_A, C_and_A_init_greedy_string_cycle, "GreedyCycleCandA"});
    initializers_meta.push_back({InitializerType::C_ONLY, C_init_weighted_random, "WeightedRandomC"});
    initializers_meta.push_back({InitializerType::C_ONLY, C_init_cyclic, "CyclicC"});
    initializers_meta.push_back({InitializerType::C_ONLY, C_init_random, "RandomC"});
    initializers_meta.push_back({InitializerType::C_ONLY, C_init_block, "BlockC"});
    
    int num_restarts = initializers_meta.size();
    bool first_solution_printed = false;

    for (int run_idx = 0; run_idx < num_restarts; ++run_idx) {
        Solution current_run_best_sol_storage; 
        double current_run_max_score = -std::numeric_limits<double>::infinity();
        std::array<double, N_FIXED> current_run_best_Q_k_values; 
        
        Random rnd_for_run(base_seed + run_idx); 
        
        double elapsed_total_so_far = overall_timer_main.get_elapsed_seconds();
        double remaining_total_time = total_time_limit_seconds - elapsed_total_so_far;
        
        if (remaining_total_time < 0.01 && run_idx > 0) break; 
        remaining_total_time = std::max(0.005, remaining_total_time); 

        double time_for_this_sa_run = remaining_total_time / std::max(1, (num_restarts - run_idx));
        
        const auto& current_initializer_meta = initializers_meta[run_idx]; 

        solve(input_data, global_precomputed,
              current_run_best_sol_storage, current_run_max_score, current_run_best_Q_k_values, 
              rnd_for_run, overall_timer_main, 
              time_for_this_sa_run, current_initializer_meta);

        if (current_run_max_score > overall_max_score) {
            overall_max_score = current_run_max_score;
            overall_best_sol = current_run_best_sol_storage; 
            overall_best_sol.print(); 
            std::cout.flush(); // Ensure it's printed immediately
            #ifdef ATCODER_DEBUG
            std::cerr << "New best score after run " << run_idx << " (" << initializers_meta[run_idx].name << "): " << std::round(overall_max_score) << " at time " << overall_timer_main.get_elapsed_seconds() << "s" << std::endl;
            #endif
            first_solution_printed = true;
        }
    }
    
    if (!first_solution_printed) { 
         Solution default_sol; // Handles M_FIXED=0 or M_FIXED > 0 appropriately
         default_sol.print(); 
         std::cout.flush();
         #ifdef ATCODER_DEBUG
         std::cerr << "Printed default solution as no improvement was found." << std::endl;
         #endif
    }
    
    #ifdef ATCODER_DEBUG
    std::cerr << "Final best score: " << std::round(overall_max_score) << std::endl;
    std::cerr << "Total execution time: " << overall_timer_main.get_elapsed_seconds() << "s" << std::endl;
    #endif

    return 0;
}

提出情報

提出日時
問題 A - Lovely Language Model
ユーザ fishylene
言語 C++ 23 (gcc 12.2)
得点 6233412
コード長 48562 Byte
結果 AC
実行時間 1981 ms
メモリ 4068 KiB

コンパイルエラー

Main.cpp: In function ‘void normalize_row_A(std::array<int, 12>&, const std::array<double, 12>&, Random&)’:
Main.cpp:354:67: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
  354 |              if (p_indices.empty() || sh_i >= p_indices.size() -1 && sh_i != 0) break; // Avoid issue if size is 0 or 1
      |                                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
Main.cpp: In function ‘void solve(const ProblemInput&, const GlobalPrecomputedData&, Solution&, double&, std::array<double, 36>&, Random&, const Timer&, double, const InitializerMeta&)’:
Main.cpp:525:100: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
  525 |                     if (predecessors_to_update.empty() || sh_i >= predecessors_to_update.size() -1 && sh_i != 0) break;
      |                                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
Main.cpp:562:100: warning: suggest parentheses around ‘&&’ within ‘||’ [-Wparentheses]
  562 |                     if (predecessors_to_update.empty() || sh_i >= predecessors_to_update.size() -1 && sh_i != 0) break;
      |                                                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~

ジャッジ結果

セット名 test_ALL
得点 / 配点 6233412 / 150000000
結果
AC × 150
セット名 テストケース
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt
ケース名 結果 実行時間 メモリ
test_0000.txt AC 1981 ms 4048 KiB
test_0001.txt AC 1981 ms 4004 KiB
test_0002.txt AC 1981 ms 4040 KiB
test_0003.txt AC 1981 ms 3884 KiB
test_0004.txt AC 1981 ms 3860 KiB
test_0005.txt AC 1981 ms 3884 KiB
test_0006.txt AC 1981 ms 4040 KiB
test_0007.txt AC 1981 ms 4060 KiB
test_0008.txt AC 1981 ms 3892 KiB
test_0009.txt AC 1981 ms 4000 KiB
test_0010.txt AC 1981 ms 3900 KiB
test_0011.txt AC 1981 ms 3936 KiB
test_0012.txt AC 1981 ms 4052 KiB
test_0013.txt AC 1981 ms 4004 KiB
test_0014.txt AC 1981 ms 4012 KiB
test_0015.txt AC 1981 ms 3896 KiB
test_0016.txt AC 1981 ms 3944 KiB
test_0017.txt AC 1981 ms 4048 KiB
test_0018.txt AC 1981 ms 3940 KiB
test_0019.txt AC 1981 ms 4056 KiB
test_0020.txt AC 1981 ms 4008 KiB
test_0021.txt AC 1981 ms 3888 KiB
test_0022.txt AC 1981 ms 4016 KiB
test_0023.txt AC 1981 ms 4008 KiB
test_0024.txt AC 1981 ms 3888 KiB
test_0025.txt AC 1981 ms 4012 KiB
test_0026.txt AC 1981 ms 3944 KiB
test_0027.txt AC 1981 ms 4004 KiB
test_0028.txt AC 1981 ms 4004 KiB
test_0029.txt AC 1981 ms 4048 KiB
test_0030.txt AC 1981 ms 4016 KiB
test_0031.txt AC 1981 ms 4008 KiB
test_0032.txt AC 1981 ms 4048 KiB
test_0033.txt AC 1981 ms 4060 KiB
test_0034.txt AC 1981 ms 3896 KiB
test_0035.txt AC 1981 ms 3888 KiB
test_0036.txt AC 1981 ms 4040 KiB
test_0037.txt AC 1981 ms 3896 KiB
test_0038.txt AC 1981 ms 3940 KiB
test_0039.txt AC 1981 ms 3888 KiB
test_0040.txt AC 1981 ms 3908 KiB
test_0041.txt AC 1981 ms 3944 KiB
test_0042.txt AC 1981 ms 4016 KiB
test_0043.txt AC 1981 ms 3944 KiB
test_0044.txt AC 1981 ms 4000 KiB
test_0045.txt AC 1981 ms 3888 KiB
test_0046.txt AC 1981 ms 4004 KiB
test_0047.txt AC 1981 ms 3944 KiB
test_0048.txt AC 1981 ms 3884 KiB
test_0049.txt AC 1981 ms 3892 KiB
test_0050.txt AC 1981 ms 3948 KiB
test_0051.txt AC 1981 ms 4008 KiB
test_0052.txt AC 1981 ms 4012 KiB
test_0053.txt AC 1981 ms 4004 KiB
test_0054.txt AC 1981 ms 4004 KiB
test_0055.txt AC 1981 ms 3896 KiB
test_0056.txt AC 1981 ms 4008 KiB
test_0057.txt AC 1981 ms 4060 KiB
test_0058.txt AC 1981 ms 4056 KiB
test_0059.txt AC 1981 ms 4012 KiB
test_0060.txt AC 1981 ms 3892 KiB
test_0061.txt AC 1981 ms 4012 KiB
test_0062.txt AC 1981 ms 3896 KiB
test_0063.txt AC 1981 ms 3944 KiB
test_0064.txt AC 1981 ms 4008 KiB
test_0065.txt AC 1981 ms 4056 KiB
test_0066.txt AC 1981 ms 3904 KiB
test_0067.txt AC 1981 ms 4056 KiB
test_0068.txt AC 1981 ms 4060 KiB
test_0069.txt AC 1981 ms 3944 KiB
test_0070.txt AC 1981 ms 4048 KiB
test_0071.txt AC 1981 ms 4016 KiB
test_0072.txt AC 1981 ms 3936 KiB
test_0073.txt AC 1981 ms 4068 KiB
test_0074.txt AC 1981 ms 3864 KiB
test_0075.txt AC 1981 ms 4008 KiB
test_0076.txt AC 1981 ms 4060 KiB
test_0077.txt AC 1981 ms 4012 KiB
test_0078.txt AC 1981 ms 4012 KiB
test_0079.txt AC 1981 ms 4004 KiB
test_0080.txt AC 1981 ms 4052 KiB
test_0081.txt AC 1981 ms 4044 KiB
test_0082.txt AC 1981 ms 4004 KiB
test_0083.txt AC 1981 ms 4024 KiB
test_0084.txt AC 1981 ms 4012 KiB
test_0085.txt AC 1981 ms 4004 KiB
test_0086.txt AC 1981 ms 4004 KiB
test_0087.txt AC 1981 ms 4032 KiB
test_0088.txt AC 1981 ms 4016 KiB
test_0089.txt AC 1981 ms 4056 KiB
test_0090.txt AC 1981 ms 3948 KiB
test_0091.txt AC 1981 ms 3888 KiB
test_0092.txt AC 1981 ms 3940 KiB
test_0093.txt AC 1981 ms 3940 KiB
test_0094.txt AC 1981 ms 3940 KiB
test_0095.txt AC 1981 ms 4012 KiB
test_0096.txt AC 1981 ms 3892 KiB
test_0097.txt AC 1981 ms 4052 KiB
test_0098.txt AC 1981 ms 3936 KiB
test_0099.txt AC 1981 ms 4052 KiB
test_0100.txt AC 1981 ms 3940 KiB
test_0101.txt AC 1981 ms 3864 KiB
test_0102.txt AC 1981 ms 3884 KiB
test_0103.txt AC 1981 ms 4040 KiB
test_0104.txt AC 1981 ms 3968 KiB
test_0105.txt AC 1981 ms 4004 KiB
test_0106.txt AC 1981 ms 3884 KiB
test_0107.txt AC 1981 ms 4012 KiB
test_0108.txt AC 1981 ms 4048 KiB
test_0109.txt AC 1981 ms 4012 KiB
test_0110.txt AC 1981 ms 4056 KiB
test_0111.txt AC 1981 ms 4004 KiB
test_0112.txt AC 1981 ms 4008 KiB
test_0113.txt AC 1981 ms 4040 KiB
test_0114.txt AC 1981 ms 4008 KiB
test_0115.txt AC 1981 ms 4052 KiB
test_0116.txt AC 1981 ms 4048 KiB
test_0117.txt AC 1981 ms 3940 KiB
test_0118.txt AC 1981 ms 3872 KiB
test_0119.txt AC 1981 ms 3952 KiB
test_0120.txt AC 1981 ms 4008 KiB
test_0121.txt AC 1981 ms 4060 KiB
test_0122.txt AC 1981 ms 4064 KiB
test_0123.txt AC 1981 ms 4064 KiB
test_0124.txt AC 1981 ms 4032 KiB
test_0125.txt AC 1981 ms 3944 KiB
test_0126.txt AC 1981 ms 4016 KiB
test_0127.txt AC 1981 ms 4052 KiB
test_0128.txt AC 1981 ms 4040 KiB
test_0129.txt AC 1981 ms 4016 KiB
test_0130.txt AC 1981 ms 4004 KiB
test_0131.txt AC 1981 ms 3980 KiB
test_0132.txt AC 1981 ms 3880 KiB
test_0133.txt AC 1981 ms 4048 KiB
test_0134.txt AC 1981 ms 3884 KiB
test_0135.txt AC 1981 ms 3888 KiB
test_0136.txt AC 1981 ms 3884 KiB
test_0137.txt AC 1981 ms 4056 KiB
test_0138.txt AC 1981 ms 4060 KiB
test_0139.txt AC 1981 ms 3944 KiB
test_0140.txt AC 1981 ms 4008 KiB
test_0141.txt AC 1981 ms 3952 KiB
test_0142.txt AC 1981 ms 3984 KiB
test_0143.txt AC 1981 ms 3884 KiB
test_0144.txt AC 1981 ms 3904 KiB
test_0145.txt AC 1981 ms 4008 KiB
test_0146.txt AC 1981 ms 4044 KiB
test_0147.txt AC 1981 ms 3948 KiB
test_0148.txt AC 1981 ms 4012 KiB
test_0149.txt AC 1981 ms 4052 KiB