G - Shopping in AtCoder store 解説 by en_translator
Once a price is fixed, the sell is solely dependent on how many people buys it, so we can rearrange \((B _ i) _ i\). Now, suppose that \(B _ 1\geq B _ 2\geq\cdots\geq B _ N\).
Obviously, it is optimal to gouge so far as the number of people who buys it does not reduce. More precisely, we can assume that the possible prices are one of \(B _ i+C _ j\) (otherwise, we can set to a higher price equal to the minimum \(B _ i+C _ j\) greater than the current price without losing a potential customer.)
Then, when \(i\) people buy the item, the gross sales is \(i(B _ i+C _ j)\). Since the maximum value over \(i=1,2,\ldots,N\) is the answer to \(j\), this problem has been boiled down to evaluating the following function \(f(x)\) at each \(x=C _ j\ (1\leq j\leq M)\): \[f(x)=\max _ {1\leq i\leq N}\left\{i(x+B _ i)\right\}.\] The problem in this form can be interpreted as a maximum value problem of the \(y\) coordinates of the intersections of \(x=C _ j\) and a set of lines \(l _ i\colon y=i(x+B _ i)\) in an \(xy\)-plane.
For a set of line \(l_i:y=a _ ix+b _ i\), the maximum \(y\) coordinate of the intersections with the line \(x=\alpha\) can be found with a method called convex Hull Trick.
The Convex Hull Trick is an algorithm to manage a set of lines by tracking a convex region \(S\coloneqq\{(x,y)\mid {}^\forall i.\ y\geq a _ ix+b _ i\}\) on an \(xy\)-plane.
In this problem, the set of liens is static, and prefetching \(C _ 1,\ldots,C _ M\) is also possible, so using the trick leads to a correct answer (no matter which of the several possible implementation courses you take).
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
int main() {
using namespace std;
unsigned N, M;
cin >> N >> M;
vector<unsigned long> B(N);
for (auto &&b : B) cin >> b;
sort(begin(B), end(B), greater<>{});
vector<tuple<unsigned long, unsigned long, unsigned long>> B_convex{{0, 1, B[0]}};
for (unsigned i{1}; i < N; ++i) {
unsigned long x, a{i + 1}, b{a * B[i]};
do {
const auto&[x_prev, a_prev, b_prev]{B_convex.back()};
x = (b_prev + a - min(b_prev + a, b + a_prev)) / (a - a_prev);
if (x_prev < x) break;
B_convex.pop_back();
} while (!empty(B_convex));
B_convex.emplace_back(x, a, b);
}
for (unsigned i{}, c; i < M; ++i) {
cin >> c;
const auto&[_, a, b]{*prev(upper_bound(begin(B_convex), end(B_convex), make_tuple(c + 1, 0UL, 0UL)))};
cout << a * c + b << " ";
}
cout << endl;
return 0;
}
投稿日時:
最終更新: