結果
| 問題 |
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 |
ソースコード
#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;
}
qwewe