結果
問題 |
No.1345 Beautiful BINGO
|
ユーザー |
![]() |
提出日時 | 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 |
ソースコード
#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; }