結果

問題 No.1568 Sushi
ユーザー qwewe
提出日時 2025-05-14 13:25:20
言語 PyPy3
(7.3.15)
結果
TLE  
実行時間 -
コード長 11,246 bytes
コンパイル時間 166 ms
コンパイル使用メモリ 82,768 KB
実行使用メモリ 52,992 KB
最終ジャッジ日時 2025-05-14 13:26:24
合計ジャッジ時間 10,631 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 4
other TLE * 1 -- * 24
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys

def solve():
    L, N, Q = map(int, sys.stdin.readline().split())
    A = list(map(int, sys.stdin.readline().split()))

    # Precompute displacements and directions
    # d_at_A[i] = displacement at time A[i] (using A[-1]=0)
    # current_A_times includes 0 and all A_i
    # current_d_values[k] is d(current_A_times[k])
    # current_dirs[k] is direction in [current_A_times[k], current_A_times[k+1])
    
    current_A_times = [0] + A
    num_segments = N + 1 # N intervals defined by N+1 points (0, A_0 ... A_{N-1})

    current_d_values = [0] * (N + 1)
    current_dirs = [0] * (N + 1)

    current_disp = 0
    current_time = 0
    direction = 1 # 1 for CCW, -1 for CW

    for i in range(N): # Iterating through N switches at A[0]...A[N-1]
        # Interval [current_time, A[i])
        # current_A_times[i] is previous A_time (or 0)
        # current_A_times[i+1] is A[i]
        
        # Displacement and direction for interval [current_A_times[i], current_A_times[i+1])
        # which is [ A_{i-1} (or 0), A_i )
        current_d_values[i] = current_disp
        current_dirs[i] = direction
        
        segment_duration = A[i] - current_time
        current_disp += direction * segment_duration
        current_time = A[i]
        direction *= -1
    
    # Last segment: from A[N-1] to infinity
    current_d_values[N] = current_disp
    current_dirs[N] = direction


    # Function to get d(t)
    def get_displacement_at_time(t):
        if t == 0:
            return 0
        
        # Find segment for t
        # Binary search for k such that current_A_times[k] <= t < current_A_times[k+1]
        # A_times = [0, A_0, A_1, ..., A_{N-1}]
        # N = len(A), current_A_times has N+1 elements from index 0 to N
        
        import bisect
        # k is such that current_A_times[k] is the latest change point <= t
        # if t is one of A_i, then it falls into the start of the segment A_i to A_{i+1}
        # bisect_right returns insertion point, k-1 is the index
        k = bisect.bisect_right(current_A_times, t) -1
        
        # if t itself is an A_i, k will be its index in current_A_times
        # e.g. t=A[0], current_A_times = [0, A[0], ...], k=1
        # d_base = current_d_values[k] which is d(current_A_times[k])
        # dir_seg = current_dirs[k]
        # time_in_seg = t - current_A_times[k]
        # disp = d_base + dir_seg * time_in_seg
        
        base_time_of_segment = current_A_times[k]
        base_disp_of_segment = current_d_values[k]
        dir_in_segment = current_dirs[k]
        
        return base_disp_of_segment + dir_in_segment * (t - base_time_of_segment)

    # Function to find smallest t_pickup >= t_place
    # such that (d(t_pickup) - d(t_place)) % L == x_customer
    # This means d(t_pickup) % L == (x_customer + d(t_place)) % L
    def find_t_pickup(t_place, x_customer_target_chair, d_at_t_place):
        if x_customer_target_chair == 0: # Takes 0 time if already at chair 0
             # This case means sushi is placed at chair 0, customer is at chair 0.
             # The time for sushi to travel from 0 to 0 is 0.
             # So t_pickup = t_place.
             return t_place

        target_d_mod_L = (x_customer_target_chair + d_at_t_place % L + L) % L
        
        min_t_found = float('inf')

        # Check k = k_approx-1, k_approx, k_approx+1
        # k_approx tries to make target_d_mod_L + k*L close to d_at_t_place
        # (or rather, d(t_pickup) is close to d(t_place))
        # So target_d_mod_L + k*L should be close to d_at_t_place
        
        # Initial estimate for d_at_t_pickup is d_at_t_place + x_customer_target_chair (short CCW path)
        # or d_at_t_place - (L - x_customer_target_chair) (short CW path)
        
        # Estimate k for d(t_pickup) = target_d_mod_L + k * L
        # If no direction changes, d(t_pickup) ~ d_at_t_place + (t_pickup - t_place)
        # t_pickup - t_place is roughly x_customer_target_chair or L - x_customer_target_chair
        # So d(t_pickup) ~ d_at_t_place + x_customer_target_chair OR d_at_t_place - (L - x_customer_target_chair)
        # Let initial_abs_disp_estimate = d_at_t_place.
        # k_center = round((initial_abs_disp_estimate - target_d_mod_L) / L) if L > 0 else 0
        
        # A simpler approach: the actual displacement d(t_f) - d(t_s) will be one of
        # x, x-L, x+L. (small number of laps)
        # So d(t_f) will be d(t_s) + x, or d(t_s) + x-L, or d(t_s) + x+L.
        
        # Iterate through possible absolute displacements d(t_f)
        # for delta_disp_target in [x_customer_target_chair, x_customer_target_chair - L, x_customer_target_chair + L]:
        #    abs_target_d_val = d_at_t_place + delta_disp_target
        
        # We need d(t) = target_d_mod_L + k*L
        # Let's estimate k. d(t) should be roughly d(t_place).
        # So target_d_mod_L + k*L approx d(t_place)
        k_base = 0
        if L > 0:
            k_base = round((d_at_t_place - target_d_mod_L) / L)

        for k_offset in [-2, -1, 0, 1, 2]: # Check a few k values around estimate
                                     # The problem constraints on L and A_i are large,
                                     # this range of k should be sufficient for typical scenarios
                                     # where sushi does not make excessive laps.
                                     # A more robust k range could be needed based on L and max travel time.
                                     # Max travel time could be L. So relative displacement is up to L.
                                     # d(t_f) - d(t_s) can be X, X-L, X+L.
                                     # D(t_f) = D(t_s) + X, D(t_s) + X-L, D(t_s) + X+L
                                     # D(t_f) = target_mod_L + k*L
                                     # So target_mod_L + k*L = D(t_s) + X (or X-L or X+L)
                                     # target_mod_L + k*L = ((target_mod_L - X) % L + L)%L + D_ts_multiple_of_L + X
                                     # This means k*L should be near D_ts_multiple_of_L.
                                     # So k should be near D_ts_multiple_of_L / L.

            abs_target_d_val = target_d_mod_L + (k_base + k_offset) * L
            
            # Find smallest t >= t_place such that d(t) = abs_target_d_val
            # Find segment for t_place
            import bisect
            seg_idx_start = bisect.bisect_right(current_A_times, t_place) - 1

            current_t_candidate = float('inf')

            for j in range(seg_idx_start, N + 1):
                seg_A_time = current_A_times[j]
                seg_d_val = current_d_values[j]
                seg_dir = current_dirs[j]
                
                # Equation: seg_d_val + seg_dir * (t - seg_A_time) = abs_target_d_val
                # seg_dir * (t - seg_A_time) = abs_target_d_val - seg_d_val
                
                if seg_dir == 0: # Should not happen if L > 0 speed is 1
                    if seg_d_val == abs_target_d_val:
                        # Stays at this displacement for whole segment
                        # Smallest t is max(t_place, seg_A_time)
                        t_sol = max(t_place, seg_A_time)
                        if j < N : # has a next segment
                             if t_sol < current_A_times[j+1]:
                                current_t_candidate = min(current_t_candidate, t_sol)
                                break 
                        else: # last segment
                            current_t_candidate = min(current_t_candidate, t_sol)
                            break
                    continue

                # t - seg_A_time = (abs_target_d_val - seg_d_val) / seg_dir
                # t = seg_A_time + (abs_target_d_val - seg_d_val) / seg_dir
                
                # (abs_target_d_val - seg_d_val) must be multiple of seg_dir (i.e. same sign or zero) for t >= seg_A_time
                # Or, more simply, (abs_target_d_val - seg_d_val) * seg_dir >= 0
                
                if seg_dir == 1:
                    time_offset_in_seg = abs_target_d_val - seg_d_val
                else: # seg_dir == -1
                    time_offset_in_seg = -(abs_target_d_val - seg_d_val) # i.e. seg_d_val - abs_target_d_val
                
                if time_offset_in_seg < 0: # Target d_val already passed in this direction
                    continue
                
                t_sol = seg_A_time + time_offset_in_seg

                # Check if t_sol is valid for this segment and >= t_place
                # Valid for segment: seg_A_time <= t_sol < next_A_time (if exists)
                # Valid for search: t_sol >= t_place
                
                actual_t_sol_start = max(t_place, seg_A_time)
                
                if t_sol < actual_t_sol_start : # Solution is before we care
                    continue

                seg_end_A_time = float('inf')
                if j < N : # N is index of last segment start (A[N-1]), N+1 is total segments
                    seg_end_A_time = current_A_times[j+1]
                
                if t_sol < seg_end_A_time:
                    current_t_candidate = min(current_t_candidate, t_sol)
                    break # Found in this segment, it's the earliest for this D_absolute
            
            min_t_found = min(min_t_found, current_t_candidate)
            
        return min_t_found

    prev_ans = 0
    results = []

    for q_idx in range(Q):
        B_i, C_i = map(int, sys.stdin.readline().split())

        x_i_actual = 0
        t_i_actual = 0

        if q_idx == 0:
            x_i_actual = B_i
            t_i_actual = C_i
        else:
            x_i_actual = (B_i + prev_ans) % L
            t_i_actual = (C_i + prev_ans) % (10**15)

        if x_i_actual == 0: # Special case as discussed
            current_ans = 0
            results.append(current_ans)
            prev_ans = current_ans
            continue

        # Candidates for t_place: t_i_actual, and potentially first A_j >= t_i_actual
        t_place_candidates = [t_i_actual]
        
        import bisect
        first_A_idx_after_ti = bisect.bisect_left(A, t_i_actual) # index in original A
        if first_A_idx_after_ti < N: # A[first_A_idx_after_ti] is an A_j >= t_i_actual
             if A[first_A_idx_after_ti] > t_i_actual : # only consider if it's strictly after. If A[idx] == t_i_actual, it's covered by t_i_actual effects
                 t_place_candidates.append(A[first_A_idx_after_ti])
        
        min_total_time_elapsed = float('inf')

        for t_place_cand in t_place_candidates:
            d_at_t_place_cand = get_displacement_at_time(t_place_cand)
            
            t_pickup_cand = find_t_pickup(t_place_cand, x_i_actual, d_at_t_place_cand)
            
            if t_pickup_cand != float('inf'):
                time_elapsed = t_pickup_cand - t_i_actual
                min_total_time_elapsed = min(min_total_time_elapsed, time_elapsed)
        
        current_ans = min_total_time_elapsed
        results.append(current_ans)
        prev_ans = current_ans

    for res in results:
        sys.stdout.write(str(res) + "\n")

solve()
0