結果

問題 No.1297 銅像
ユーザー qwewe
提出日時 2025-05-14 13:12:44
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 8,173 bytes
コンパイル時間 842 ms
コンパイル使用メモリ 95,764 KB
実行使用メモリ 7,848 KB
最終ジャッジ日時 2025-05-14 13:13:45
合計ジャッジ時間 5,698 ms
ジャッジサーバーID
(参考情報)
judge2 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 7 TLE * 1 -- * 13
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <numeric>
#include <algorithm>
#include <cmath> // Required for abs function

using namespace std;

// Use long long for costs as they can potentially exceed the range of a 32-bit integer.
// The problem statement specifies costs up to 10^12, and total cost can accumulate.
typedef long long ll;

// Define a sufficiently large value to represent infinity.
// The maximum possible total cost can be estimated. Suppose one craftsman builds all statues.
// Max cost could be roughly N * (max(a_i) + max_transport + max(b_i))
// Max transport cost is roughly N * C <= 10^5 * 10^6 = 10^11.
// Max cost ~ 10^5 * (10^12 + 10^11 + 10^12) ~ 10^5 * (2.1 * 10^12) ~ 2.1 * 10^17.
// This value fits within a 64-bit signed long long (max value ~9e18).
// We use 4e18 as a safe upper bound constant for INF, significantly larger than max possible cost.
const ll INF = 4e18; 

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

    int N; // Number of islands and craftsmen
    ll C;  // Cost factor for transportation
    cin >> N >> C;

    // Store work fees (a_i) and design fees (b_i) for each craftsman i.
    // Using 0-based indexing for vectors a and b.
    vector<ll> a(N), b(N);
    for (int i = 0; i < N; ++i) {
        cin >> a[i] >> b[i];
    }

    // Dynamic Programming approach based on the observation that there exists an optimal solution
    // where the assignments are monotone: if craftsman i_j builds the statue on island j,
    // then i_j <= i_{j+1} for all j=1..N-1.
    // Let DP[j][k] be the minimum cost to build statues on islands 1 to j,
    // such that island j is assigned to craftsman k. The assignments for 1..j satisfy monotonicity.
    //
    // We can optimize space complexity by only keeping track of the DP values for the previous island (j-1)
    // to compute the values for the current island (j).
    // Use 1-based indexing for islands (j) and craftsmen (k) in DP states for clarity, matching the problem statement.
    
    // current_dp[k] will store DP[j][k] during computation for island j
    vector<ll> current_dp(N + 1, INF);
    // prev_dp[k] stores DP[j-1][k] from the previous island j-1
    vector<ll> prev_dp(N + 1, INF);
    
    // M_prev[k] will store the prefix minimum: min_{p=1..k} prev_dp[p]
    // This helps compute the transition efficiently.
    vector<ll> M_prev(N + 1, INF); 

    // Base case: j=1 (first island)
    // Calculate the cost if island 1 is assigned to craftsman k (k=1..N)
    for (int k = 1; k <= N; ++k) {
        // Transportation cost for craftsman k (at location k) to build on island 1 (at location 1)
        // Explicitly cast indices to ll to avoid potential intermediate overflow issues if N is large.
        ll transport_cost = abs((ll)k - 1LL) * C; 
        
        // Total cost = work fee a_k + transport cost + design fee b_k
        // The design fee b_k is always paid because this is the first time craftsman k is used in this path.
        // Access arrays a and b using 0-based index k-1.
        // Check for potential overflow before each addition.
        ll current_cost = a[k - 1];
        // Check if adding transport_cost overflows
        if (transport_cost > INF - current_cost) { 
             prev_dp[k] = INF; // Set to INF if overflow would occur
        } else {
            current_cost += transport_cost;
             // Check if adding design_fee b[k-1] overflows
            if (b[k - 1] > INF - current_cost) {
                prev_dp[k] = INF; // Set to INF if overflow would occur
            } else {
                prev_dp[k] = current_cost + b[k - 1];
            }
        }
    }

    // Compute DP table row by row, iterating through islands j from 2 to N
    for (int j = 2; j <= N; ++j) {
        // Compute prefix minima M_prev based on the DP values from the previous row (prev_dp corresponds to DP[j-1])
        M_prev[0] = INF; // Initialize base case for prefix minimum calculation
        for(int k = 1; k <= N; ++k) {
            M_prev[k] = min(M_prev[k-1], prev_dp[k]);
        }

        // Calculate current row DP values (current_dp corresponds to DP[j])
        fill(current_dp.begin(), current_dp.end(), INF); // Initialize current row DP values with INF
        
        // Iterate through all possible craftsmen k for island j
        for (int k = 1; k <= N; ++k) {
            // Calculate the cost incurred specifically for assigning island j to craftsman k.
            // This includes the work fee a_k and transportation cost |k-j|*C.
            ll variable_cost = a[k - 1]; // Work fee
            ll transport_cost = abs((ll)k - (ll)j) * C; // Transportation cost
            
            // Check for overflow when calculating variable_cost
            if (transport_cost > INF - variable_cost) { 
                 variable_cost = INF; // Use INF if overflow occurs
            } else {
                 variable_cost += transport_cost;
            }

            // If variable cost itself is INF (due to overflow or large base values), skip update for this k.
            if (variable_cost == INF) { 
                 continue;
            }

            // The recurrence relation for DP[j][k] is:
            // DP[j][k] = (a_k + C|k-j|) + min( DP[j-1][k],  b_k + min_{p=1..k-1} DP[j-1][p] )
            // This considers two possibilities for the state reaching (j, k):
            
            // Option 1: The craftsman for island j-1 was also k.
            // The cost is DP[j-1][k] + variable_cost_for_j.
            // Design fee b_k is already included in DP[j-1][k] if k was used.
            ll cost1 = INF;
            if (prev_dp[k] != INF) { // Check if the previous state is reachable
                 // Check for potential overflow before adding variable_cost
                 if (variable_cost > INF - prev_dp[k]) {
                     // cost1 remains INF if overflow would occur
                 } else {
                     cost1 = variable_cost + prev_dp[k];
                 }
            }

            // Option 2: The craftsman for island j-1 was p, where p < k.
            // The cost is min_{p=1..k-1} DP[j-1][p] + b_k + variable_cost_for_j.
            // The term min_{p=1..k-1} DP[j-1][p] is efficiently retrieved using M_prev[k-1].
            // The design fee b_k must be added because craftsman k is used for the first time
            // in the sequence of craftsmen when transitioning from p < k to k.
            ll cost2 = INF;
             if (M_prev[k - 1] != INF) { // Check if any path ending with p < k is reachable
                 ll min_prev_cost_prefix = M_prev[k - 1];
                 ll design_fee = b[k - 1];
                 
                 // Check for overflow when adding design fee b_k
                 if (min_prev_cost_prefix > INF - design_fee) { 
                     // If min_prev_cost + design_fee overflows, this path cost is effectively INF
                 } else {
                     ll combined_prev_cost = min_prev_cost_prefix + design_fee;
                     // Check for potential overflow when adding variable_cost
                     if (variable_cost > INF - combined_prev_cost) {
                        // cost2 remains INF if overflow would occur
                     } else {
                         cost2 = variable_cost + combined_prev_cost;
                     }
                 }
             }

            // The DP value DP[j][k] is the minimum cost from either Option 1 or Option 2.
            current_dp[k] = min(cost1, cost2);
        }
        
        // Update prev_dp for the next iteration (j+1). The computed 'current_dp' becomes the 'prev_dp'.
        prev_dp = current_dp;
    }

    // The final minimum total cost is the minimum value in the last row of the DP table (j=N),
    // minimized over all possible craftsmen k assigned to the last island N.
    ll min_total_cost = INF;
    // After the loop for j=N finishes, prev_dp holds the DP[N] values
    for (int k = 1; k <= N; ++k) {
        min_total_cost = min(min_total_cost, prev_dp[k]); 
    }

    cout << min_total_cost << endl;

    return 0;
}
0