結果
問題 |
No.703 ゴミ拾い Easy
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:13:48 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 93 ms / 1,500 ms |
コード長 | 9,580 bytes |
コンパイル時間 | 1,660 ms |
コンパイル使用メモリ | 87,712 KB |
実行使用メモリ | 12,672 KB |
最終ジャッジ日時 | 2025-05-14 13:14:40 |
合計ジャッジ時間 | 6,240 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 4 |
other | AC * 46 |
ソースコード
#include <iostream> #include <vector> #include <deque> #include <string> #include <algorithm> // For std::reverse // Use __int128_t for intermediate calculations in CHT check to avoid overflow. // This type is typically available in GCC and Clang. #ifdef __GNUC__ using int128 = __int128_t; #else // Fallback for compilers that don't support __int128_t. This is risky and might lead to overflow. // On platforms like AtCoder, Codeforces, this should generally work. using int128 = long long; // #warning "__int128_t not supported, using long long which might overflow." // You might want to uncomment this warning locally #endif // Function to print __int128_t (useful for local debugging, not typically needed for online judge submissions) #ifdef __GNUC__ std::ostream& operator<<(std::ostream& os, int128 val) { if (val == 0) return os << "0"; bool negative = false; if (val < 0) { negative = true; val = -val; // Make positive } std::string s; while (val > 0) { s += (char)('0' + val % 10); val /= 10; } if (negative) os << "-"; // Reverse the string to get the correct order of digits std::reverse(s.begin(), s.end()); // Handle case where original value was 0, and after making positive it is still 0. if (s.empty() && !negative) return os << "0"; return os << s; } #endif // State variables long long N; // Number of trash items and volunteers std::vector<long long> a; // x-coordinates of volunteers std::vector<long long> x; // x-coordinates of trash items std::vector<long long> y; // y-coordinates of trash items std::vector<long long> dp; // DP table: dp[i] stores minimum cost to collect trash 0..i-1 // Structure representing a line y = mx + c in the CHT struct Line { long long m; // slope (-2 * x_j) long long c; // y-intercept (dp[j] + x_j^2 + y_j^2) }; // Function to evaluate a line at a given x-coordinate (query_a) // Uses 128-bit intermediate type to prevent overflow during multiplication. long long eval(const Line& line, long long query_a) { int128 val = (int128)line.m * query_a + line.c; // Final result is expected to fit within long long based on problem constraints analysis. return (long long)val; } // Convexity check function for CHT. // Determines if adding line `r` after line `q` maintains the lower envelope property, // given that line `p` comes before `q`. // Returns true if `q` should be kept (convexity holds), false if `q` is redundant and should be removed. bool check(const Line& p, const Line& q, const Line& r) { // The condition for convexity (q being useful) is that the intersection point of (p, q) // is less than or equal to the intersection point of (q, r). // Intersection point x* = (c2 - c1) / (m1 - m2) // We want x*_pq <= x*_qr => (q.c - p.c) / (p.m - q.m) <= (r.c - q.c) / (q.m - r.m) // Assuming slopes are strictly decreasing (p.m > q.m > r.m), both denominators are positive. // Cross-multiplying gives: (q.c - p.c) * (q.m - r.m) <= (r.c - q.c) * (p.m - q.m) // This form avoids floating point numbers and uses 128-bit integers to prevent overflow. int128 cq_minus_cp = (int128)q.c - p.c; int128 mq_minus_mr = (int128)q.m - r.m; int128 cr_minus_cq = (int128)r.c - q.c; int128 mp_minus_mq = (int128)p.m - q.m; // Perform the check using 128-bit integers int128 val1 = cq_minus_cp * mq_minus_mr; int128 val2 = cr_minus_cq * mp_minus_mq; // The inequality val1 <= val2 determines if q should be kept. // This check is robust even if some slopes are equal due to properties of inequalities, // as long as the insertion logic correctly handles dominated lines with equal slopes first. return val1 <= val2; } int main() { // Optimize standard IO operations std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); // Read input size std::cin >> N; // Handle the edge case N=0 if (N == 0) { std::cout << 0 << std::endl; return 0; } // Resize vectors and read input data a.resize(N); x.resize(N); y.resize(N); for (int i = 0; i < N; ++i) std::cin >> a[i]; for (int i = 0; i < N; ++i) std::cin >> x[i]; for (int i = 0; i < N; ++i) std::cin >> y[i]; // Initialize DP table. dp[i] stores minimum cost for trash 0...i-1. dp.resize(N + 1); dp[0] = 0; // Base case: cost is 0 for collecting 0 trash items. // Deque to maintain the lower envelope of lines for CHT std::deque<Line> hull; // Add the first line L_0 corresponding to the base case (j=0) long long x0 = x[0]; long long y0 = y[0]; Line l0; l0.m = -2 * x0; // Explicitly cast squares to long long to avoid potential intermediate overflow if x0, y0 were large ints. l0.c = dp[0] + (long long)x0 * x0 + (long long)y0 * y0; hull.push_back(l0); // Iterate through the DP states from i=1 to N for (int i = 1; i <= N; ++i) { // The current query point is the x-coordinate of person i-1 long long current_a = a[i - 1]; // Query Step: Find the line in the hull that gives the minimum value at current_a. // Since query points 'a' are non-decreasing and slopes 'm' are non-increasing, // we can efficiently find the minimum by removing lines from the front of the deque. while (hull.size() >= 2) { // Get the first two lines from the deque Line l1 = hull[0]; Line l2 = hull[1]; // If slopes are equal, remove the one with larger intercept (less optimal). if (l1.m == l2.m) { if (l1.c >= l2.c) { // L1 is above or same as L2 hull.pop_front(); // Remove L1 } else { // L1 is below L2 // L1 is better. L2 is suboptimal but might be needed later. Keep both for now. // But L1 will be the minimum found. Stop removing from front. break; } } else { // Slopes are different. Since CHT maintains decreasing slopes, l1.m > l2.m. // Check if L1 is worse than or equal to L2 at current_a. // Use the condition: current_a >= intersection_x point of L1 and L2 // Equivalent cross-multiplication form: current_a * (m1 - m2) >= c2 - c1 int128 lhs = (int128)(l1.m - l2.m) * current_a; int128 rhs = (int128)l2.c - l1.c; if (lhs >= rhs) { // L1 is worse or equal than L2 at current_a hull.pop_front(); // Remove L1 as it's no longer optimal } else { // L1 is strictly better than L2 at current_a break; // L1 is the optimal line for this query point } } } // The line at the front of the deque is now the optimal one for current_a long long min_val = eval(hull.front(), current_a); // Calculate dp[i] using the found minimum value. Use 128-bit intermediate for safety. dp[i] = (long long)((int128)current_a * current_a + min_val); // Add Step: Add a new line corresponding to the state dp[i] for future computations. // This line will be based on trash item i. This happens only if i < N. if (i < N) { long long xi = x[i]; long long yi = y[i]; Line new_line; new_line.m = -2 * xi; // Calculate intercept c = dp[i] + x_i^2 + y_i^2. Use long long casts for squares. new_line.c = dp[i] + (long long)xi * xi + (long long)yi * yi; bool add_this_line = true; // Flag to track if the new line should be added // Before adding, handle lines with the same slope as the new line. // Remove lines from the back if they have the same slope and are dominated (>= intercept). while (!hull.empty() && hull.back().m == new_line.m) { if (hull.back().c >= new_line.c) { // Existing line at back is worse or equal hull.pop_back(); // Remove it } else { // Existing line at back is better (smaller intercept) add_this_line = false; // New line is dominated, don't add it break; // Stop checking and skip adding } } // Only proceed if the new line is not dominated by an existing line with same slope if(add_this_line) { // Maintain convexity: Remove lines from the back that become redundant after adding the new line. while (hull.size() >= 2) { Line p = hull[hull.size() - 2]; // Second to last line Line q = hull.back(); // Last line // Call the check function to see if q remains useful with new_line (r) if (!check(p, q, new_line)) { // If check returns false, q is redundant hull.pop_back(); // Remove q } else { // Convexity holds with q break; // Stop removing } } // Add the new line to the back of the deque hull.push_back(new_line); } // If add_this_line was false, we skip adding the line. } } // The final answer is the minimum cost to collect all N trash items (0..N-1). std::cout << dp[N] << std::endl; return 0; }