結果
問題 |
No.1211 円環はお断り
|
ユーザー |
![]() |
提出日時 | 2025-05-14 12:59:50 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 7,972 bytes |
コンパイル時間 | 1,107 ms |
コンパイル使用メモリ | 101,516 KB |
実行使用メモリ | 48,360 KB |
最終ジャッジ日時 | 2025-05-14 13:02:10 |
合計ジャッジ時間 | 41,572 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 32 TLE * 9 |
ソースコード
#include <iostream> #include <vector> #include <numeric> #include <cmath> #include <algorithm> // Include for std::max using namespace std; // Use long long for potentially large sums typedef long long ll; int N; // Number of beads int K; // Number of segments (people) vector<ll> A; // Bead values // Using a tripled array allows handling the cyclic nature by using linear indices. // A segment starting near the end of the original N beads can wrap around, // represented continuously in the tripled array. vector<ll> A_triple; vector<ll> P_triple; // Prefix sums for the tripled array // Jump[p][k] stores the starting index of the segment after 2^k segments, // starting from index p. This is used for binary lifting. vector<vector<int>> Jump; // K <= 10^5, log2(10^5) is approx 16.6. Max power k needed is 16. // MAX_LOG_K = 17 covers k=0..16. Using 18 is safer just in case. const int MAX_LOG_K = 18; // Check function: Determines if it's possible to partition the ring into K segments // such that each segment's sum is at least X. bool can(ll X) { // If X is 0, it's trivially possible as long as we can partition (N>=K>=1 holds). if (X == 0) return true; // Calculate Next[p] for p in [0, 3N-1). // Next[p] is the starting index of the segment that follows the segment starting at p. // If segment starts at p and ends at q, Next[p] = q+1. // All indices are 0-based. vector<int> Next(3 * N); int q = 0; // Use two pointers technique: q tracks the potential end index of the segment starting at p. for (int p = 0; p < 3 * N; ++p) { // Ensure the segment end index q is at least the start index p. q = max(p, q); // Find the minimum index q >= p such that the sum of beads A[p...q] >= X. // Use prefix sums for efficient sum calculation: P_triple[q+1] - P_triple[p] >= X. // Also, a segment cannot be longer than N beads (the whole ring). Thus, q must be < p + N. while (q < p + N && P_triple[q + 1] - P_triple[p] < X) { q++; // Extend the segment end index q } if (q >= p + N) { // If q reaches p+N, it means even taking N consecutive beads starting from p (effectively the whole ring), // the sum is less than X. This happens only if total_sum < X. // In this case, it's impossible to form a segment with sum >= X starting at p. // Mark this path as failed using an out-of-bounds index (>= 3N). Next[p] = 3 * N; } else { // Found a valid segment ending at q. The next segment must start at index q+1. Next[p] = q + 1; } } // Initialize the Jump table base case (k=0: jump of 2^0=1 step/segment) // Jump[p][0] stores the index after 1 segment starting from p. for (int p = 0; p < 3 * N; ++p) { Jump[p][0] = Next[p]; } // Fill the rest of the Jump table using dynamic programming (binary lifting) // Jump[p][k] = starting index after 2^k segments, starting from p. // Computed by combining two jumps of 2^(k-1) steps. for (int k = 1; k < MAX_LOG_K; ++k) { for (int p = 0; p < 3 * N; ++p) { // intermediate = position after 2^(k-1) steps starting from p int intermediate = Jump[p][k-1]; // Check if the intermediate index is already out of bounds (>= 3N). // This signifies a failed path earlier. if (intermediate >= 3 * N) { Jump[p][k] = 3 * N; // Propagate the out-of-bounds state } else { // Compute the jump of 2^k steps by chaining two 2^(k-1) jumps: // p -> intermediate -> Jump[intermediate][k-1] Jump[p][k] = Jump[intermediate][k-1]; } } } // Check each possible starting bead index p from 0 to N-1 for (int p = 0; p < N; ++p) { int current_p = p; // The starting index for this sequence of segments int k_steps = K; // Total number of segments (steps) needed // Use binary lifting to find the final position after K segments for(int k = MAX_LOG_K - 1; k >= 0; --k) { // Check if the k-th bit of K is set (i.e., if 2^k contributes to K) if ((k_steps >> k) & 1) { // Before accessing Jump table, ensure current position is valid if (current_p >= 3 * N) { // If current position is already out of bounds, this path has failed. Stop processing. break; } // Make a jump of 2^k segments current_p = Jump[current_p][k]; } } // After K steps, current_p is the starting index of the (K+1)-th segment. // The K segments covered beads from the original index p up to current_p - 1. // The total number of beads covered is current_p - p. // A valid partition exists if this total span is at most N beads. // This condition ensures the K segments fit within one traversal of the ring without "overlapping" in terms of total length. if (current_p - p <= N) { return true; // Found a valid partition starting at p. X is achievable. } } // If no starting position p from 0..N-1 leads to a valid partition, X is not achievable. return false; } int main() { // Use faster I/O operations ios_base::sync_with_stdio(false); cin.tie(NULL); // Read input N and K cin >> N >> K; A.resize(N); // Resize vector A to hold N bead values ll total_sum = 0; // Calculate total sum of bead values bool non_zero_exists = false; // Flag to check if any bead has positive value for (int i = 0; i < N; ++i) { cin >> A[i]; total_sum += A[i]; if (A[i] > 0) non_zero_exists = true; } // Edge case: If all bead values are 0, the only possible minimum sum M is 0. if (!non_zero_exists) { cout << 0 << endl; return 0; } // Create tripled array A_triple. This simplifies handling the ring structure. // Indices [0, N-1] hold the original array. // Indices [N, 2N-1] hold a copy. // Indices [2N, 3N-1] hold another copy. A_triple.resize(3 * N); for (int i = 0; i < 3 * N; ++i) { A_triple[i] = A[i % N]; } // Compute prefix sums for the tripled array. P_triple[k] = sum of A_triple[0...k-1]. // Size 3N+1 needed for P_triple[q+1] - P_triple[p] calculation where q can be up to 3N-1. P_triple.resize(3 * N + 1, 0); for (int i = 0; i < 3 * N; ++i) { P_triple[i + 1] = P_triple[i] + A_triple[i]; } // Allocate memory for the Jump table. Size 3N is needed because intermediate indices can reach up to 3N. // Rows correspond to starting indices p (0 to 3N-1). Columns correspond to jump power k (0 to MAX_LOG_K-1). Jump.assign(3 * N, vector<int>(MAX_LOG_K)); // Binary search for the maximum possible minimum segment sum M (denoted as 'ans'). // The search range is [0, total_sum]. The upper bound is total_sum + 1 for the binary search logic. ll low = 0, high = total_sum + 1, ans = 0; while (low < high) { // Calculate midpoint carefully to avoid potential overflow if low/high are large. ll mid = low + (high - low) / 2; if (can(mid)) { // If a minimum sum of 'mid' is possible, 'mid' is a potential answer. // We try to find a larger possible minimum sum, so update lower bound. ans = mid; low = mid + 1; } else { // If 'mid' is not possible, the maximum possible minimum sum must be smaller. // Update upper bound. high = mid; } } // Output the final answer, which is the largest 'mid' for which can(mid) returned true. cout << ans << endl; return 0; }