結果

問題 No.155 生放送とBGM
ユーザー qwewe
提出日時 2025-05-14 13:08:10
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
AC  
実行時間 395 ms / 6,000 ms
コード長 10,252 bytes
コンパイル時間 730 ms
コンパイル使用メモリ 86,944 KB
実行使用メモリ 18,048 KB
最終ジャッジ日時 2025-05-14 13:09:55
合計ジャッジ時間 3,564 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 15
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <string>
#include <numeric>
#include <iomanip>
#include <cstdio> // For sscanf

using namespace std;

// Define types for clarity and potential future changes
typedef long long ll;
// Use long double for higher precision floating point arithmetic
typedef long double ld;

// Precomputed combinations table C(n, k)
// Using a fixed size array based on max N=50
ll combinations_table[51][51];

// Function to precompute combinations using Pascal's identity
// C(n, k) = C(n-1, k-1) + C(n-1, k)
void precompute_combinations(int N_max) {
    // Ensure N_max doesn't exceed allocated array size
    if (N_max > 50) N_max = 50; 

    for (int i = 0; i <= N_max; ++i) {
        combinations_table[i][0] = 1; // Base case: C(i, 0) = 1
        for (int j = 1; j <= i; ++j) {
            // Check for potential overflow before adding.
            // With N <= 50, the maximum value C(50, 25) is approx 1.26e14, which fits within a 64-bit long long.
            // So standard addition should be safe. We add the check just in case.
             if (combinations_table[i-1][j] > __LONG_LONG_MAX__ - combinations_table[i-1][j-1]) {
                 // Handle overflow - Set to MAX or throw error.
                 // For competitive programming contexts, we often rely on problem constraints ensuring intermediate values fit standard types.
                 combinations_table[i][j] = __LONG_LONG_MAX__; // Indicate overflow
             } else {
                 combinations_table[i][j] = combinations_table[i-1][j-1] + combinations_table[i-1][j];
             }
        }
    }
}

// Function to retrieve combinations value C(n, k) from the precomputed table
ll combinations(int n, int k) {
    // Basic validation for indices n and k
    if (k < 0 || k > n || n < 0 || n > 50) return 0;
    
    // Return the precomputed value. Assuming no overflow occurred during computation.
    return combinations_table[n][k];
}

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

    int N; // Number of songs
    int L_minutes; // Broadcast length in minutes
    cin >> N >> L_minutes;

    vector<int> T_songs(N); // Vector to store song lengths in seconds
    ll S_total = 0; // Total length of all songs in seconds
    for (int i = 0; i < N; ++i) {
        string s; // Song length input in MM:SS format
        cin >> s;
        int mm, ss;
        // Parse the MM:SS string using sscanf
        sscanf(s.c_str(), "%d:%d", &mm, &ss);
        T_songs[i] = mm * 60 + ss; // Convert MM:SS to total seconds
        
        // Constraint check: MM:SS != 00:00 means T_songs[i] > 0.
        // Add assertion or check if needed, though problem statement guarantees this.
        // if (T_songs[i] <= 0) { /* handle error or invalid input */ }

        S_total += T_songs[i]; // Accumulate total length of all songs
    }

    // Calculate total broadcast duration in seconds
    ll T_broadcast = (ll)L_minutes * 60; 

    // Handle edge case: If broadcast time is 0, no songs can be played. Expected value is 0.
    if (T_broadcast == 0) {
         cout << fixed << setprecision(10) << 0.0 << endl;
         return 0;
    }

    // Handle edge case: If N=0 or total song length S_total is 0 (only possible if all T_k=0, disallowed by constraints)
    if (N == 0 || S_total <= 0) { 
         cout << fixed << setprecision(10) << 0.0 << endl;
         return 0;
    }

    // Case: If broadcast duration is long enough to play all songs at least once (one full cycle).
    // This occurs if T_broadcast >= S_total. In this case, all N songs are guaranteed to be played.
    if (T_broadcast >= S_total) {
        cout << fixed << setprecision(10) << (ld)N << endl;
        return 0;
    }
    
    // Main case: T_broadcast < S_total.
    // We need to calculate the expected number of distinct songs played using DP.
    
    // Precompute combinations C(n,k) up to N.
    precompute_combinations(N);

    // DP state: C_counts[j][s] stores the number of subsets of songs of size j with total length exactly s.
    // Dimensions: (N+1) for number of songs j (from 0 to N), (T_broadcast+1) for sum s (from 0 to T_broadcast).
    vector<vector<ll>> C_counts(N + 1, vector<ll>(T_broadcast + 1, 0));
    C_counts[0][0] = 1; // Base case: There's 1 way to choose 0 songs with total sum 0 (the empty set).

    // Fill the DP table C_counts using all N songs. This is a variation of the subset sum / knapsack problem.
    for(int i = 0; i < N; ++i) { // Iterate through each song T_songs[i] (0-indexed)
        int current_song_len = T_songs[i];
        
        // Update the DP table considering the inclusion of song i.
        // Iterate j (number of songs in subset) downwards from N to 1.
        for (int j = N; j >= 1; --j) { 
            // Iterate s (total sum) downwards from T_broadcast to current_song_len.
            for (int s = T_broadcast; s >= current_song_len; --s) {
                // If there exists a subset of size j-1 with sum s-current_song_len...
                if (C_counts[j-1][s - current_song_len] > 0) {
                    // ...then we can form a subset of size j with sum s by adding song i.
                    // Add the count. Check for potential overflow before adding.
                     if (C_counts[j-1][s - current_song_len] > __LONG_LONG_MAX__ - C_counts[j][s]) {
                          C_counts[j][s] = __LONG_LONG_MAX__; // Indicate overflow if it occurs
                     } else {
                          C_counts[j][s] += C_counts[j-1][s - current_song_len];
                     }
                }
            }
        }
    }

    // Calculate the overall expected value E[X] = sum P(E_k) for k=1..N
    ld total_expected_value = 0.0;

    // Iterate through each song k (0-indexed) to calculate its probability P(E_k) of being played.
    for (int k = 0; k < N; ++k) { 
        int Tk = T_songs[k]; // Length of the current song k
        
        // DP state: Ck_counts[j][s] = number of subsets of S\{k} (all songs except k) of size j with sum s.
        // Dimensions: N for j (0 to N-1 songs), T_broadcast+1 for s.
        vector<vector<ll>> Ck_counts(N, vector<ll>(T_broadcast + 1, 0)); 
        Ck_counts[0][0] = 1; // Base case: empty subset for j=0, s=0.

        // Compute Ck_counts using the recurrence relation: C_k(j, s) = C(j, s) - C_k(j-1, s - Tk)
        // C(j, s) is the count using all N songs (stored in C_counts)
        // C_k(j-1, s - Tk) is count of subsets from S\{k} size j-1 sum s-Tk.
        for (int j = 1; j <= N - 1; ++j) { // Compute counts row by row for j from 1 to N-1
            for (int s = 0; s <= T_broadcast; ++s) { // Compute counts for each sum s
                // Initialize Ck_counts[j][s] with C_counts[j][s] (subsets from full set)
                Ck_counts[j][s] = C_counts[j][s];
                
                // If sum s is large enough to potentially subtract the term C_k(j-1, s-Tk)
                if (s >= Tk) { 
                     // Check if C_k(j-1, s - Tk) is positive before subtracting
                     if (Ck_counts[j-1][s - Tk] > 0) {
                         // Basic sanity check: ensure subtraction doesn't result in negative count.
                         // This should not happen with correct logic and exact integer arithmetic.
                         if (Ck_counts[j-1][s - Tk] > Ck_counts[j][s]) {
                            // Indicates an issue, likely C(j, s) < Ck(j-1, s-Tk), which is impossible.
                            // Could hint at prior overflow or logic error. Clamp to 0 as fallback.
                            Ck_counts[j][s] = 0; 
                         } else {
                            // Subtract the count of subsets including song k to get count of subsets excluding k.
                            Ck_counts[j][s] -= Ck_counts[j-1][s - Tk];
                         }
                     }
                }
                 // Another safety check: ensure count is non-negative after subtraction.
                 if (Ck_counts[j][s] < 0) {
                      Ck_counts[j][s] = 0; // Clamp to 0 if negative.
                 }
            }
        }

        // Calculate the sum of probabilities component for song k: sum_{j=0}^{N-1} p_{k,j}
        // where p_{k,j} = P(sum of random j songs from S\{k} < T_broadcast)
        ld Pk_sum_probs = 0.0; // Accumulator for this sum
        for (int j = 0; j <= N - 1; ++j) { // Iterate over prefix size j (number of songs preceding k)
            ll sum_s_count = 0; // Count subsets of S\{k} of size j with sum < T_broadcast
            // Sum the counts Ck_counts[j][s] for s from 0 up to T_broadcast - 1
            for (int s = 0; s < T_broadcast; ++s) { 
                 if(Ck_counts[j][s] > 0) { // Add only positive counts
                    // Check for potential overflow before summing up counts.
                     if (Ck_counts[j][s] > __LONG_LONG_MAX__ - sum_s_count) {
                          sum_s_count = __LONG_LONG_MAX__; // Indicate overflow
                          break; // Stop summing for this j if overflow detected
                     } else {
                           sum_s_count += Ck_counts[j][s];
                     }
                 }
            }
            
            // If sum overflowed, the result might be inaccurate. Assuming it fits long long.

            // Total number of ways to choose j songs from N-1 songs (the set S\{k})
            ll num_subsets = combinations(N - 1, j); 
            
            // Calculate probability p_{k,j} = sum_s_count / num_subsets
            // Avoid division by zero if num_subsets is 0.
            if (num_subsets > 0) {
                ld p_kj = (ld)sum_s_count / num_subsets; 
                Pk_sum_probs += p_kj; // Add p_{k,j} to the sum for song k
            }
        }
        
        // The probability song k is played is P(E_k) = (1/N) * Pk_sum_probs
        // Add this probability to the total expected value.
        total_expected_value += Pk_sum_probs / N;
    }

    // Output the final calculated expected value with the required precision.
    cout << fixed << setprecision(10) << total_expected_value << endl;

    return 0;
}
0