結果
| 問題 |
No.705 ゴミ拾い Hard
|
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 2025-05-14 13:24:45 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 6,009 bytes |
| コンパイル時間 | 1,320 ms |
| コンパイル使用メモリ | 100,804 KB |
| 実行使用メモリ | 15,096 KB |
| 最終ジャッジ日時 | 2025-05-14 13:25:47 |
| 合計ジャッジ時間 | 5,172 ms |
|
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 4 |
| other | AC * 18 WA * 22 |
ソースコード
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <cmath> // For std::abs
// Using __int128_t for dp values and costs
using int128 = __int128_t;
// Helper to print __int128_t
std::ostream& operator<<(std::ostream& os, int128 val) {
if (val == 0) {
os << "0";
return os;
}
std::string s = "";
bool neg = false;
if (val < 0) {
neg = true;
val = -val;
}
while (val > 0) {
s += (char)((val % 10) + '0'); // Explicit cast to char
val /= 10;
}
if (neg) {
s += '-';
}
std::reverse(s.begin(), s.end());
os << s;
return os;
}
int N_val;
std::vector<long long> A_vals, X_vals, Y_vals;
std::vector<int128> dp_vals;
// Using a large constant for infinity. Max possible sum is ~6e20.
// __int128 max is much larger (~1.7e38). This INF allows some additions.
const int128 INF = ((int128)1 << 120);
// Function to calculate base^3 safely using int128
int128 power3(long long base) {
int128 v = base; // Promote to int128 before multiplication
return v * v * v;
}
// Cost for person p_idx to collect garbage starting at g_idx (0-indexed)
// The range collected is g_idx, ..., p_idx.
int128 calculate_cost_for_segment(int p_idx, int g_idx) {
long long diff_x = A_vals[p_idx] - X_vals[g_idx];
long long val_y = Y_vals[g_idx]; // Y_vals[g_idx] is non-negative as per constraints
int128 term_x = power3(std::abs(diff_x));
int128 term_y = power3(val_y);
return term_x + term_y;
}
void solve_dp(int p_low, int p_high, int k_opt_low, int k_opt_high) {
if (p_low > p_high) {
return;
}
int p_mid = p_low + (p_high - p_low) / 2;
int best_k_for_pmid = -1;
// dp_vals[p_mid] is already INF. If it remains INF, best_k_for_pmid is not updated.
// We need a valid best_k_for_pmid for recursive calls.
// Initialize best_k_for_pmid to ensure it's within the valid range for k.
// e.g. k_opt_low, or more restrictively current_k_search_low.
int current_k_search_low = k_opt_low;
int current_k_search_high = std::min(p_mid, k_opt_high);
// Initialize best_k_for_pmid to a value in the current search range to ensure it's valid
// even if dp_vals[p_mid] remains INF.
if (current_k_search_low <= current_k_search_high) {
best_k_for_pmid = current_k_search_low; // Default, can be any in range
} else {
// If search range is empty, dp_vals[p_mid] will remain INF.
// Pass conservative k_opt ranges to children.
// best_k_for_pmid = k_opt_low for left child, k_opt_high for right child.
// This case is complex, better to ensure best_k_for_pmid is always set if loop runs.
// If loop doesn't run current_k_search_low > current_k_search_high:
// Left call: solve_dp(p_low, p_mid - 1, k_opt_low, k_opt_high);
// Right call: solve_dp(p_mid + 1, p_high, k_opt_low, k_opt_high);
// But the problem guarantees a solution, so this path for empty search range
// should not be the sole path to finite solution.
// The Knuth property should ensure k_opt_low <= k_opt_high.
// A safe default for best_k_for_pmid if no k improves dp_vals[p_mid] from INF:
best_k_for_pmid = k_opt_low; // Defaulting to k_opt_low
}
for (int k = current_k_search_low; k <= current_k_search_high; ++k) {
// k is the starting garbage index for person p_mid.
// It must be non-negative. This is ensured as k_opt_low starts at 0
// and subsequent k_opt_low/high are from previous best_k (which are >=0).
int128 prev_dp_val = (k == 0) ? 0 : dp_vals[k - 1];
if (prev_dp_val == INF) { // If the previous state is unreachable, skip
continue;
}
int128 cost_of_segment = calculate_cost_for_segment(p_mid, k);
// Check for overflow before addition if prev_dp_val or cost_of_segment is huge
// But INF + finite_cost is still INF.
if (cost_of_segment == INF) continue; // Should not happen with problem constraints
int128 current_total_cost = prev_dp_val + cost_of_segment;
if (current_total_cost < dp_vals[p_mid]) {
dp_vals[p_mid] = current_total_cost;
best_k_for_pmid = k;
}
}
// After finding optimal k for p_mid, recurse.
// If dp_vals[p_mid] is INF, best_k_for_pmid might not be "optimal" but a valid index.
// If no k was found (current_k_search_low > current_k_search_high), dp_vals[p_mid] stays INF.
// best_k_for_pmid should be set to k_opt_low for left child, and k_opt_high for right child's opt_k range.
// The logic: best_k_for_pmid is set to a valid k if dp_vals[p_mid] is updated.
// If dp_vals[p_mid] remains INF, we can use k_opt_low for left call's upper bound on k,
// and k_opt_high for right call's lower bound for k to pass on the widest possible valid range.
// However, standard D&C opt relies on best_k_for_pmid being the actual argmin.
// If dp[p_mid] is INF, any k in its search range is "optimal" for INF.
// The choice of best_k_for_pmid = k_opt_low (or current_k_search_low) before loop handles this.
solve_dp(p_low, p_mid - 1, k_opt_low, best_k_for_pmid);
solve_dp(p_mid + 1, p_high, best_k_for_pmid, k_opt_high);
}
int main() {
std::ios_base::sync_with_stdio(false);
std::cin.tie(NULL);
std::cin >> N_val;
A_vals.resize(N_val);
X_vals.resize(N_val);
Y_vals.resize(N_val);
dp_vals.assign(N_val, INF);
for (int i = 0; i < N_val; ++i) std::cin >> A_vals[i];
for (int i = 0; i < N_val; ++i) std::cin >> X_vals[i];
for (int i = 0; i < N_val; ++i) std::cin >> Y_vals[i];
if (N_val == 0) { // Edge case, though constraints say N >= 1
std::cout << 0 << std::endl;
return 0;
}
solve_dp(0, N_val - 1, 0, N_val - 1);
std::cout << dp_vals[N_val - 1] << std::endl;
return 0;
}
qwewe