結果
問題 |
No.155 生放送とBGM
|
ユーザー |
![]() |
提出日時 | 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 |
ソースコード
#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; }