D - パレードの撮影 / Photographing the Parade Editorial by admin
Claude 4.6 Opus (Thinking)Overview
This problem asks you to select the optimal shooting day from day \(0\) to day \(D\) that minimizes the frame width required to capture all \(N\) floats moving along a straight road. There are \(Q\) parameter changes, and you need to find the optimal solution for each version.
Analysis
Understanding the properties of F(d)
The frame width on day \(d\) is:
\[F(d) = \max_{i}(X_i + V_i \cdot d + L_i) - \min_{i}(X_i + V_i \cdot d - L_i)\]
Here is a key observation:
- \(\max_{i}(X_i + V_i \cdot d + L_i)\) is the maximum of linear functions → This is a convex function with respect to \(d\) (upper envelope of line segments)
- \(\min_{i}(X_i + V_i \cdot d - L_i)\) is the minimum of linear functions → This is a concave function with respect to \(d\) (lower envelope of line segments)
Therefore \(F(d) = (\text{convex function}) - (\text{concave function}) = (\text{convex function}) + (\text{convex function})\), so \(F(d)\) is a convex function.
Minimizing a convex function
Since a convex function has a “valley” shape, we can efficiently find its minimum on the interval \([0, D]\). A brute-force search takes \(O(D)\) which is TLE since \(D \le 10^9\), but using ternary search, we can find the minimum with \(O(\log D)\) evaluations.
Meaning of the constraint \(N(Q+1) \le 5 \times 10^5\)
Evaluating \(F(d)\) once for each version takes \(O(N)\). Since we perform solve across all \((Q+1)\) versions, the total cost per evaluation is \(O(N(Q+1) \cdot \log D)\). Because the constraint keeps \(N(Q+1)\) bounded by \(5 \times 10^5\), this is sufficiently fast.
Algorithm
- eval(d): Loop through all floats to compute the frame width \(F(d)\) on day \(d\) in \(O(N)\)
- solve(): Use ternary search to find the minimum of the convex function \(F(d)\)
- Divide the interval \([lo, hi]\) into thirds and evaluate \(F\) at the intermediate points \(m_1, m_2\)
- If \(F(m_1) \le F(m_2)\), the minimum is in \([lo, m_2]\); otherwise it is in \([m_1, hi]\)
- When the interval width becomes less than 3, check all remaining candidates
- After each modification, update the parameters and call solve() again
Intuitive explanation of ternary search
A convex function is monotonically decreasing to the left of the minimum and monotonically increasing to the right. For \(m_1 < m_2\), if \(F(m_1) > F(m_2)\), the minimum must be to the right of \(m_1\), so we can narrow down to \(lo = m_1\). The reverse case works similarly.
Complexity
- Time complexity: \(O(N(Q+1) \cdot \log D)\)
- Ternary search performs \(O(\log_{3/2} D) \approx 50\) evaluations, each taking \(O(N)\)
- Total across all versions: \(5 \times 10^5 \times 50 \approx 2.5 \times 10^7\)
- Space complexity: \(O(N)\)
Implementation Notes
Termination condition for integer ternary search: Loop while
hi - lo >= 3, then brute-force check the remaining few points. For integers, when the interval becomes too small, dividing into thirds may not work correctly, so exhaustive enumeration at the end is safe.Overflow prevention: Since \(V_i \cdot d\) can be as large as \(10^6 \times 10^9 = 10^{15}\), use
long long.Update handling: Simply modify the arrays directly (each modification is applied cumulatively).
Source Code
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, D, Q;
cin >> N >> D >> Q;
vector<long long> X(N), V(N), L(N);
for(int i = 0; i < N; i++){
cin >> X[i] >> V[i] >> L[i];
}
auto eval = [&](long long d) -> long long {
long long mx = LLONG_MIN, mn = LLONG_MAX;
for(int i = 0; i < N; i++){
long long upper = X[i] + V[i]*d + L[i];
long long lower = X[i] + V[i]*d - L[i];
if(upper > mx) mx = upper;
if(lower < mn) mn = lower;
}
return mx - mn;
};
auto solve = [&]() -> long long {
long long lo = 0, hi = D;
while(hi - lo >= 3){
long long m1 = lo + (hi - lo) / 3;
long long m2 = hi - (hi - lo) / 3;
if(eval(m1) <= eval(m2)){
hi = m2;
} else {
lo = m1;
}
}
long long ans = LLONG_MAX;
for(long long d = lo; d <= hi; d++){
long long v = eval(d);
if(v < ans) ans = v;
}
return ans;
};
cout << solve() << "\n";
for(int q = 0; q < Q; q++){
int p;
long long a, b, c;
cin >> p >> a >> b >> c;
p--;
X[p] = a;
V[p] = b;
L[p] = c;
cout << solve() << "\n";
}
return 0;
}
This editorial was generated by claude4.6opus-thinking.
posted:
last update: