結果
問題 |
No.1211 円環はお断り
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:25:40 |
言語 | PyPy3 (7.3.15) |
結果 |
TLE
|
実行時間 | - |
コード長 | 5,310 bytes |
コンパイル時間 | 171 ms |
コンパイル使用メモリ | 82,976 KB |
実行使用メモリ | 262,780 KB |
最終ジャッジ日時 | 2025-05-14 13:27:08 |
合計ジャッジ時間 | 40,322 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 33 TLE * 8 |
ソースコード
import sys def solve(): N, K = map(int, sys.stdin.readline().split()) A = list(map(int, sys.stdin.readline().split())) if N == 0: # Based on constraints 1 <= K <= N, N cannot be 0. print(0) return A_double = A + A # Max K is N (10^5). log2(10^5) approx 16.6. # So, we need powers up to 2^16 (dp table rows 0 to 16). Size 17. # LOG_MAX_K_CONST determines number of rows in dp table. LOG_MAX_K_CONST = 18 # Sufficient for K up to 2^17-1. Covers K <= 10^5. # infinity_val indicates a pointer beyond A_double or failure to form segment. # A_double indices are 0 to 2*N-1. # next_start[j] can be 2*N if segment A[j...2*N-1] is valid, and next starts "at" 2*N. # Or 2*N if no segment can be formed. infinity_val = 2 * N # memo_can_check = {} # Optional: memoization for can() if N is small, but not needed here. def can(m_test): # if m_test in memo_can_check: return memo_can_check[m_test] # 1. Calculate next_start array using two pointers. # next_s[j] = p, where segment A_double[j...p-1] has sum >= m_test, and p is smallest such. # p is the exclusive end index (start of the next segment). # If no such segment, p = infinity_val. next_s = [infinity_val] * (2 * N) current_sum = 0 right_ptr = 0 # Exclusive end of the current window [left_ptr, right_ptr) for left_ptr in range(2 * N): # Expand window to the right until sum >= m_test or end of A_double while right_ptr < 2 * N and current_sum < m_test: current_sum += A_double[right_ptr] right_ptr += 1 if current_sum >= m_test: next_s[left_ptr] = right_ptr # else: next_s[left_ptr] remains infinity_val (initialized) # Shrink window from the left for the next iteration # current_sum is for window [left_ptr, right_ptr) # For next iteration (left_ptr+1), sum will be for [left_ptr+1, right_ptr) current_sum -= A_double[left_ptr] # If A_double[left_ptr] was very large, current_sum could become negative. # However, A_i >= 1, so this won't make sum negative unless m_test itself is strange. # No need for `if current_sum < 0: current_sum = 0` if A_i positive. # 2. Build DP table for jumps (binary lifting) # dp[k][i] = end position (start of next segment) after 2^k segments, starting from i. # dp table dimensions: LOG_MAX_K_CONST rows, 2*N + 1 columns (for index 2*N = infinity_val) dp = [[infinity_val] * (2 * N + 1) for _ in range(LOG_MAX_K_CONST)] # Base case: dp[0][i] is one jump for i in range(2 * N): dp[0][i] = next_s[i] dp[0][infinity_val] = infinity_val # dp[0][2*N] = 2*N, ensures infinity propagates # Fill DP table for k_power in range(1, LOG_MAX_K_CONST): for i in range(2 * N + 1): # Iterate up to 2*N (infinity_val index) intermediate_pos = dp[k_power-1][i] # intermediate_pos will be an index from 0 to 2*N. # dp[k_power-1] is defined for all these indices. dp[k_power][i] = dp[k_power-1][intermediate_pos] # 3. Check for each starting position s in the original circle for s_original_idx in range(N): # s_original_idx is the start in A_double as well current_pos = s_original_idx # Perform K jumps using the DP table temp_K = K for k_bit_idx in range(LOG_MAX_K_CONST): if (temp_K >> k_bit_idx) & 1: # If 2^(k_bit_idx) is part of K current_pos = dp[k_bit_idx][current_pos] # If current_pos becomes infinity_val, it will stay infinity_val # due to dp[...][infinity_val] = infinity_val. # After K jumps, current_pos is the start of the (K+1)-th segment. # The K segments are A_double[s_original_idx ... current_pos-1]. # Total number of beads used = current_pos - s_original_idx. # We need this to be at most N. # This condition also implicitly checks if current_pos < infinity_val, # because if current_pos = infinity_val (2*N), then 2*N - s_original_idx <= N # implies N <= s_original_idx, which is false since s_original_idx < N. if (current_pos - s_original_idx) <= N: # memo_can_check[m_test] = True return True # memo_can_check[m_test] = False return False # Binary search for M low = 1 # Max possible M is sum of all A's (for K=1). Max sum A_i = 10^9, N=10^5 => sum ~ 10^14. high = 0 for x_val in A: high += x_val ans = 0 # Stores the maximum M found so far. while low <= high: mid = low + (high - low) // 2 if mid == 0: # Should not happen as low starts at 1 and A_i >= 1 (so high >= 1) low = 1 continue if can(mid): ans = mid low = mid + 1 # Try for a larger M else: high = mid - 1 # M is too large sys.stdout.write(str(ans) + "\n") solve()