結果

問題 No.1912 Get together 2
ユーザー qwewe
提出日時 2025-05-14 13:05:00
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 207 ms / 2,000 ms
コード長 6,244 bytes
コンパイル時間 846 ms
コンパイル使用メモリ 87,076 KB
実行使用メモリ 34,508 KB
最終ジャッジ日時 2025-05-14 13:06:48
合計ジャッジ時間 5,960 ms
ジャッジサーバーID
(参考情報)
judge1 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 33
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm> // for max

using namespace std;

// Define long long for potentially large values, as sums of squares can exceed 32-bit integer limits.
typedef long long ll;

int main() {
    // Fast IO setup to speed up input reading.
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N; // Number of slimes
    int M; // Number of boxes
    cin >> N >> M;

    vector<ll> V(N); // Values of slimes
    for (int i = 0; i < N; ++i) {
        cin >> V[i];
    }

    // Group slimes based on their compatibility pattern (represented as a bitmask).
    // Use a map to store the total value for each unique pattern mask encountered.
    // The key is the bitmask, the value is the sum of values of slimes with that pattern.
    map<int, ll> W_map;
    for (int i = 0; i < N; ++i) {
        string S; // Compatibility string for slime i
        cin >> S;
        int mask = 0;
        // Convert the compatibility string S to a bitmask.
        // If S[j] == 'o', the slime is compatible with box j+1. We set the j-th bit in the mask.
        // We use 0-indexed bits for boxes 0 to M-1. So box j corresponds to bit j.
        for (int j = 0; j < M; ++j) {
            if (S[j] == 'o') {
                mask |= (1 << j); 
            }
        }
        // Add the slime's value V[i] to the total value associated with this mask.
        // The problem guarantees each slime is compatible with at least one box, so mask > 0.
        if (mask > 0) {
             W_map[mask] += V[i];
        }
    }

    // Create a vector W of size 2^M to store the total values for each mask.
    // W[mask] = total value of slimes whose compatibility pattern is exactly 'mask'.
    vector<ll> W(1 << M, 0);
    for (auto const& [mask, total_value] : W_map) {
       W[mask] = total_value;
    }

    // Compute F[mask] = sum of W[sub] for all submasks 'sub' of 'mask'.
    // This is done using Sum Over Subsets (SOS) Dynamic Programming.
    // F[mask] represents the total value of all slimes that can *only* be placed in boxes belonging to the set represented by 'mask'.
    vector<ll> F = W; // Initialize F with the values from W. F[mask] starts as W[mask].

    // SOS DP calculation:
    // Iterate through each bit position (dimension) from 0 to M-1.
    for (int i = 0; i < M; ++i) { 
        // Iterate through all possible masks from 0 to 2^M - 1.
        for (int mask = 0; mask < (1 << M); ++mask) {
            // If the i-th bit is set in 'mask', it means mask includes the dimension 'i'.
            // We update F[mask] by adding the value from the mask without the i-th bit set (F[mask ^ (1 << i)]).
            // This accumulates the values from all submasks.
            if ((mask >> i) & 1) {
                F[mask] += F[mask ^ (1 << i)];
            }
        }
    }
    // After this loop, F[mask] correctly stores the sum of W[sub] for all submasks 'sub' of 'mask'.

    // The main dynamic programming part to calculate the maximum sum of squares.
    // dp[mask] will store the maximum sum of squares achievable using only boxes represented in 'mask',
    // and considering only slimes whose compatibility patterns 'p' are subsets of 'mask' (p subseteq mask).
    vector<ll> dp(1 << M, 0); // Initialize dp table with 0s. The minimum possible score is 0.

    // We compute the dp states iteratively. The value dp[mask] is computed based on values of dp[submask].
    // The following loop structure implements the DP relation efficiently in O(M * 2^M).
    // Iterate through all masks from 0 up to 2^M - 1.
    for (int mask = 0; mask < (1 << M); ++mask) {
         // Base case dp[0] = 0 is handled by initialization.
         // For mask > 0, calculate its dp value based on its immediate submasks.
         if (mask == 0) continue;
         
         // Iterate through each bit 'i' that is set in the current mask.
         for (int i=0; i<M; ++i) {
              if ((mask >> i) & 1) { // Check if the i-th bit is set in mask (i.e., box 'i' is in the set 'mask')
                  // Consider the state corresponding to the mask without box 'i'.
                  int prev_mask = mask ^ (1 << i); 
                  
                  // Calculate the total value of slimes whose patterns 'p' satisfy:
                  // p is a subset of 'mask', AND p is NOT a subset of 'prev_mask'.
                  // This difference F[mask] - F[prev_mask] represents exactly these slimes.
                  // These slimes must be compatible with box 'i' (and possibly others in 'prev_mask').
                  ll value_group = F[mask] - F[prev_mask]; 
                  
                  // The DP transition considers the possibility of grouping all slimes corresponding to 'value_group'
                  // and assigning them conceptually together. The score contribution is value_group^2.
                  // We take the maximum over all possible ways to remove a box 'i' to form 'prev_mask'.
                  // This update rule effectively finds the optimal partitioning according to the structure discovered.
                  dp[mask] = max(dp[mask], dp[prev_mask] + value_group * value_group);
              }
         }
    }

    /* Alternative equivalent DP loop structure that builds up from smaller masks to larger masks:
       This structure was validated during thought process and also works.
       Initialize dp with 0s.
       for (int mask = 0; mask < (1 << M) - 1; ++mask) { // Iterate masks from 0 to 2^M - 2
           for (int i = 0; i < M; ++i) { // Iterate through bits/boxes
               if (!((mask >> i) & 1)) { // If box 'i' is NOT in current mask
                   int next_mask = mask | (1 << i); // Create mask including box 'i'
                   ll value_group = F[next_mask] - F[mask]; // Value of slimes needing box 'i' newly
                   // Update the dp value for the larger mask
                   dp[next_mask] = max(dp[next_mask], dp[mask] + value_group * value_group);
               }
           }
       }
    */

    // The final answer is the maximum score achievable using all M boxes, which is stored in dp[(1 << M) - 1].
    cout << dp[(1 << M) - 1] << endl;

    return 0;
}
0