結果

問題 No.484 収穫
ユーザー qwewe
提出日時 2025-05-14 13:11:00
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
WA  
実行時間 -
コード長 9,005 bytes
コンパイル時間 1,011 ms
コンパイル使用メモリ 92,608 KB
実行使用メモリ 6,272 KB
最終ジャッジ日時 2025-05-14 13:12:52
合計ジャッジ時間 2,848 ms
ジャッジサーバーID
(参考情報)
judge1 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2 WA * 1
other AC * 12 WA * 9
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath> // Include for abs

using namespace std;

// Define long long type for potentially large times
typedef long long ll;

// Check function determines if it's possible to harvest all fruits by time T.
// It checks four types of paths for each possible starting cell s:
// 1. Start at s, go to cell 1, then sweep linearly to cell N.
// 2. Start at s, go to cell N, then sweep linearly to cell 1.
// 3. Start at s, go to cell 1, sweep to N, then sweep back to 1.
// 4. Start at s, go to cell N, sweep to 1, then sweep back to N.
// The function incorporates waiting times: if arriving at cell i at time t_arrive < A[i-1],
// the agent must wait until A[i-1]. The time recorded is the finish time at cell i.
bool check(ll T, int N, const vector<ll>& A) {
    // Basic check: If any fruit ripens after time T, it's impossible.
    for (int i = 0; i < N; ++i) {
        if (A[i] > T) {
            return false;
        }
    }
    
    // Special case: If there's only one cell.
    if (N == 1) {
        // The time needed is simply the ripening time of the single fruit.
        return A[0] <= T;
    }

    // Iterate through all possible starting cells s (from 1 to N).
    for (int s = 1; s <= N; ++s) {
        
        // Check path type 1: s -> ... -> 1 -> ... -> N
        // Calculate time to reach cell 1 from start s.
        ll time_to_reach_1 = (ll)abs(s - 1);
        // Calculate the time when harvest at cell 1 finishes. Max of arrival time and ripening time.
        ll finish_time_at_1 = max(time_to_reach_1, A[0]);
        
        bool possible_1N = true;
        // If finishing at cell 1 already exceeds T, this path is impossible.
        if (finish_time_at_1 > T) {
             possible_1N = false;
        } else {
            ll prev_finish_time = finish_time_at_1;
            // Calculate finish times for cells 2 to N.
            for (int i = 2; i <= N; ++i) {
                // Arrive at cell i at time prev_finish_time + 1.
                // Finish harvest at cell i at time max(arrival_time, A[i-1]).
                ll current_finish_time = max(prev_finish_time + 1, A[i - 1]);
                // If finish time exceeds T, impossible.
                if (current_finish_time > T) {
                    possible_1N = false;
                    break;
                }
                prev_finish_time = current_finish_time;
            }
            // If the loop completed, prev_finish_time holds the finish time at cell N. Check if it's <= T.
             if (possible_1N && prev_finish_time <= T) {
                  return true; // This path type works for starting cell s.
             }
             // Need to reset possible_1N flag check based on final time condition.
             if (possible_1N && prev_finish_time > T) {
                 possible_1N = false; // Final check, although inner loop checks this too
             }
        }
       
        // Check path type 2: s -> ... -> N -> ... -> 1
        // Similar logic as path type 1, but sweeping from N to 1.
        ll time_to_reach_N = (ll)abs(s - N);
        ll finish_time_at_N = max(time_to_reach_N, A[N - 1]);
        
        bool possible_N1 = true;
        if (finish_time_at_N > T) {
             possible_N1 = false;
        } else {
            ll prev_finish_time = finish_time_at_N;
            for (int i = N - 1; i >= 1; --i) {
                ll current_finish_time = max(prev_finish_time + 1, A[i - 1]);
                if (current_finish_time > T) {
                    possible_N1 = false;
                    break;
                }
                 prev_finish_time = current_finish_time;
            }
             if (possible_N1 && prev_finish_time <= T) {
                 return true; // This path type works.
             }
             if (possible_N1 && prev_finish_time > T) {
                  possible_N1 = false;
             }
        }
    
        // Check path type 3: s -> ... -> 1 -> ... -> N -> ... -> 1 (Two sweeps)
        vector<ll> T_F(N + 1); // Stores finish time at cell i during forward sweep (1 to N)
        
        ll time_to_reach_1_sweep1 = (ll)abs(s - 1);
        T_F[1] = max(time_to_reach_1_sweep1, A[0]);
        
        bool possible_1N_sweep = true;
        if (T_F[1] > T) {
             possible_1N_sweep = false;
        } else {
            // Calculate finish times for forward sweep (1 to N).
            for (int i = 2; i <= N; ++i) {
                T_F[i] = max(T_F[i-1] + 1, A[i-1]);
                 if (T_F[i] > T) {
                     possible_1N_sweep = false;
                     break;
                 }
            }
        }

        // If the first sweep (1 to N) is possible within time T:
        if (possible_1N_sweep) {
             // Start backward sweep (N to 1) from cell N. Finish time at N is T_F[N].
             ll prev_finish_time_B = T_F[N];
             bool possible_N1_sweep = true;
             
             // Calculate finish times for backward sweep (N to 1).
             for (int i = N - 1; i >= 1; --i) {
                ll current_finish_time_B = max(prev_finish_time_B + 1, A[i - 1]); 
                 if (current_finish_time_B > T) {
                     possible_N1_sweep = false;
                     break;
                 }
                 prev_finish_time_B = current_finish_time_B;
             }
             
             // If the second sweep completed within time T:
             if (possible_N1_sweep) {
                 // The final time is the finish time at cell 1 (end of second sweep).
                 if (prev_finish_time_B <= T) return true; // This path type works.
             }
        }

        // Check path type 4: s -> ... -> N -> ... -> 1 -> ... -> N (Two sweeps)
        vector<ll> T_B2(N + 1); // Stores finish time at cell i during backward sweep first (N to 1)

        ll time_to_reach_N_first = (ll)abs(s - N);
        T_B2[N] = max(time_to_reach_N_first, A[N-1]);

        bool possible_N1_sweep2 = true;
        if (T_B2[N] > T) {
             possible_N1_sweep2 = false;
        } else {
             // Calculate finish times for first sweep (N to 1).
             for (int i = N - 1; i >= 1; --i) {
                T_B2[i] = max(T_B2[i + 1] + 1, A[i - 1]);
                 if (T_B2[i] > T) {
                     possible_N1_sweep2 = false;
                     break;
                 }
             }
        }

        // If the first sweep (N to 1) is possible within time T:
        if(possible_N1_sweep2){
             // Start forward sweep (1 to N) from cell 1. Finish time at 1 is T_B2[1].
             ll prev_finish_time_F2 = T_B2[1];
             bool possible_1N_sweep2 = true;
            
             // Calculate finish times for second sweep (1 to N).
             for (int i = 2; i <= N; ++i) {
                ll current_finish_time_F2 = max(prev_finish_time_F2 + 1, A[i - 1]);
                 if (current_finish_time_F2 > T) {
                     possible_1N_sweep2 = false;
                     break;
                 }
                 prev_finish_time_F2 = current_finish_time_F2;
             }
             
             // If the second sweep completed within time T:
             if (possible_1N_sweep2) {
                  // The final time is the finish time at cell N (end of second sweep).
                  if (prev_finish_time_F2 <= T) return true; // This path type works.
             }
        }
     }

    // If none of the checked path types work for any starting cell s, return false.
    return false;
}


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

    int N; // Number of cells
    cin >> N;
    vector<ll> A(N); // Ripening times for each cell
    ll max_A = 0; // Keep track of the maximum ripening time
    for (int i = 0; i < N; ++i) {
        cin >> A[i];
        max_A = max(max_A, A[i]);
    }

    // Binary search for the minimum time T.
    // The lowest possible time is the maximum ripening time.
    ll low = max_A; 
    // A safe upper bound: max ripening time + generous travel time.
    // Travel time can be at most related to N sweeps, maybe O(N^2) or O(N).
    // Using max_A + 2*N*N as a very safe upper bound estimate. Add a small constant buffer.
    ll high = max_A + 2LL * N * N + 5; 
    ll ans = high; // Initialize answer to the upper bound

    // Standard binary search loop
    while (low <= high) {
        // Calculate midpoint carefully to avoid overflow
        ll mid = low + (high - low) / 2;
        
        // Check if it's possible to finish by time 'mid'
        if (check(mid, N, A)) {
            // If possible, 'mid' is a potential answer. Try smaller times.
            ans = mid;
            high = mid - 1;
        } else {
            // If not possible, need more time. Increase lower bound.
            low = mid + 1;
        }
    }

    // Output the minimum time found.
    cout << ans << endl;

    return 0;
}
0