結果

問題 No.1345 Beautiful BINGO
ユーザー qwewe
提出日時 2025-05-14 13:15:41
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 8,010 bytes
コンパイル時間 1,110 ms
コンパイル使用メモリ 102,816 KB
実行使用メモリ 19,712 KB
最終ジャッジ日時 2025-05-14 13:17:06
合計ジャッジ時間 5,446 ms
ジャッジサーバーID
(参考情報)
judge1 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 21 TLE * 1 -- * 39
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <bitset>
#include <map> // Include map if using standard map for caching
#include <unordered_map> // Include unordered_map for potentially faster caching
#include <algorithm>
#include <limits> // For numeric_limits to initialize minimum cost

using namespace std;

// Define compile-time constants based on the maximum possible N (N=16)
// This is necessary because std::bitset requires a compile-time size.
const int MAXN_COMPILE = 16;
// Maximum number of cells in the grid (N*N)
const int MAX_CELLS_COMPILE = MAXN_COMPILE * MAXN_COMPILE; // 16*16 = 256
// Maximum number of lines (N rows + N columns + 2 diagonals)
const int MAX_LINES_COMPILE = 2 * MAXN_COMPILE + 2; // 2*16 + 2 = 34

// Global variables
long long A[MAXN_COMPILE][MAXN_COMPILE]; // Store the input cost matrix
long long cell_costs[MAX_CELLS_COMPILE]; // Flattened 1D array for cell costs for easier access by index
int N; // Actual grid size from input (will be <= MAXN_COMPILE)
int N_squared; // Cached value of N*N

// Array of bitsets, where each bitset represents the set of cells belonging to a line
bitset<MAX_CELLS_COMPILE> line_masks[MAX_LINES_COMPILE];

// Cache to store computed costs for cell sets (bitsets). Using unordered_map for potentially better performance.
// Key: bitset representing a subset of cells. Value: total cost for opening these cells.
unordered_map<bitset<MAX_CELLS_COMPILE>, long long> cost_cache;

// Function to compute the total cost for opening a given set of cells S, represented by a bitset.
// Uses caching to avoid recomputing costs for the same set of cells.
long long compute_cost(const bitset<MAX_CELLS_COMPILE>& S) {
    // Check if the cost for this bitset S is already in the cache
    auto cache_it = cost_cache.find(S);
    if (cache_it != cost_cache.end()) {
        // If found, return the cached cost
        return cache_it->second;
    }

    long long current_cost = 0;
    // Iterate through all possible cell indices (0 to N*N - 1)
    for (int k = 0; k < N_squared; ++k) {
        // If the k-th bit is set in S, it means cell k is included in the set
        if (S.test(k)) { 
            // Add the cost of cell k to the total cost
            current_cost += cell_costs[k];
        }
    }
    
    // Store the newly computed cost in the cache before returning
    cost_cache[S] = current_cost;
    return current_cost;
}


int main() {
    // Use fast I/O operations
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int M; // Required minimum number of completed lines
    cin >> N >> M; // Read grid size N and minimum lines M
    N_squared = N * N; // Cache N*N

    // Read the cost matrix A and populate the flattened cell_costs array
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            cin >> A[i][j];
            // Map 2D index (i, j) to 1D index k = i*N + j
            cell_costs[i * N + j] = A[i][j];
        }
    }

    int line_idx = 0; // Initialize index for the line_masks array
    // Precompute bitmasks representing the cells for each row
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            line_masks[line_idx].set(i * N + j); // Set the bit corresponding to cell (i, j)
        }
        line_idx++; // Move to the next line index
    }
    // Precompute bitmasks for each column
    for (int j = 0; j < N; ++j) {
        for (int i = 0; i < N; ++i) {
             line_masks[line_idx].set(i * N + j); // Set the bit for cell (i, j)
        }
        line_idx++;
    }
    // Precompute bitmask for the Main Diagonal (top-left to bottom-right)
    for (int i = 0; i < N; ++i) {
         line_masks[line_idx].set(i * N + i); // Set the bit for cell (i, i)
    }
    line_idx++;
    // Precompute bitmask for the Anti-Diagonal (top-right to bottom-left)
    for (int i = 0; i < N; ++i) {
         // The cell is (i, N-1-i)
         line_masks[line_idx].set(i * N + (N - 1 - i)); 
    }
    line_idx++;

    int total_lines = line_idx; // The total number of lines is 2N+2
    
    // Divide the lines into two halves for the meet-in-the-middle approach
    int num_lines_A = total_lines / 2;
    int num_lines_B = total_lines - num_lines_A;

    // --- Meet-in-the-Middle Part 1: Generate states for the first half of lines ---
    vector<pair<bitset<MAX_CELLS_COMPILE>, int>> list_A; // Stores pairs of (cell_mask, line_count)
    int limit_A = 1 << num_lines_A; // Total number of subsets for the first half = 2^(num_lines_A)
    list_A.reserve(limit_A); // Reserve memory to potentially speed up vector insertions
    
    // Iterate through all possible subsets of the first half lines using bitmask 'i'
    for (int i = 0; i < limit_A; ++i) { 
        bitset<MAX_CELLS_COMPILE> current_S_A; // Stores the union of cells for the current subset of lines
        int current_k_A = 0; // Counts the number of lines in the current subset
        // Check each line in the first half
        for (int j = 0; j < num_lines_A; ++j) {
            // If the j-th bit of 'i' is set, it means the j-th line is included in this subset
            if ((i >> j) & 1) { 
                current_k_A++; // Increment line count
                current_S_A |= line_masks[j]; // Union the cells of this line into the combined mask
            }
        }
        // Store the generated cell mask and the number of lines completed
        list_A.push_back({current_S_A, current_k_A}); 
    }

    // --- Meet-in-the-Middle Part 2: Generate states for the second half of lines ---
    vector<pair<bitset<MAX_CELLS_COMPILE>, int>> list_B; // Stores pairs of (cell_mask, line_count)
    int limit_B = 1 << num_lines_B; // Total number of subsets for the second half = 2^(num_lines_B)
    list_B.reserve(limit_B); // Reserve memory
    
    // Iterate through all possible subsets of the second half lines using bitmask 'i'
     for (int i = 0; i < limit_B; ++i) { 
        bitset<MAX_CELLS_COMPILE> current_S_B; // Combined cell mask
        int current_k_B = 0; // Line count
        // Check each line in the second half
        for (int j = 0; j < num_lines_B; ++j) {
             // If the j-th bit of 'i' is set, include this line
            if ((i >> j) & 1) { 
                current_k_B++;
                // The lines in the second half start at index num_lines_A in the line_masks array
                current_S_B |= line_masks[num_lines_A + j]; // Union cells
            }
        }
        // Store the generated mask and line count
        list_B.push_back({current_S_B, current_k_B}); 
    }

    // --- Combine results from both halves ---
    // Initialize minimum total cost to the maximum possible value for a long long
    long long min_total_cost = numeric_limits<long long>::max();

    // Iterate through all pairs of states (one from list_A, one from list_B)
    for (const auto& pA : list_A) { 
        const bitset<MAX_CELLS_COMPILE>& S_A = pA.first; // Cell mask from the first half state
        int k_A = pA.second; // Line count from the first half state

        for (const auto& pB : list_B) { 
            const bitset<MAX_CELLS_COMPILE>& S_B = pB.first; // Cell mask from the second half state
            int k_B = pB.second; // Line count from the second half state

            // Check if the total number of completed lines (k_A + k_B) meets the requirement M
            if (k_A + k_B >= M) {
                // Calculate the union of cells required by both halves using bitwise OR
                bitset<MAX_CELLS_COMPILE> S_union = S_A | S_B;
                // Compute the cost for this combined set of cells (using the cache)
                long long current_total_cost = compute_cost(S_union);
                
                // Update the overall minimum cost if the current combination is cheaper
                min_total_cost = min(min_total_cost, current_total_cost);
            }
        }
    }
    
    // Output the minimum total cost found
    cout << min_total_cost << endl;

    return 0;
}
0