C - 魔法使い高橋君
問題
n 個の気温を変える魔法があり, i 番目の魔法は「気温を ai 度上げてから bi 度下げる」という効果がある.
最初気温は 0 度で,ここから各魔法を好きな順番で一度ずつ唱える.
このとき,途中の気温の最大値を最小化せよ.
制約
- 1≤n≤105
- 1≤ai,bi≤109
考察
座布団 DP のように,隣接する要素について「スワップしても損しない」ような条件を考える.
まず ai−bi の正負,すなわち魔法を唱えた後気温が下がるかどうかに着目する.
もしも ai−bi≥0,ai+1−bi+1<0 なら,この 2 要素はスワップした方が良い.これは以下から従う。,
max(ai,ai−bi+ai+1)≥max(ai,ai+1)≥max(ai+1−bi+1+ai,ai+1)
よって前半に ai−bi<0 のもの,後半に ai−bi≥0 のものを詰めて良いことが分かった.後はこの中で最適な並べ方を考えればいい.
まず ai−bi<0 の方から.実はこのとき,「 ai について昇順に並べる」のが最善.これは ai>ai+1 のとき以下より従う。
max(ai+1,ai+1−bi+1+ai)≤max(ai,ai+1)=ai=max(ai,ai−bi+ai+1)(∵ai+1−bi+1≤0)(∵ai>ai+1≥ai−bi+ai+1)
そして ai−bi≥0 の方も,後ろから考えれば bi−ai≤0 なので「後ろから bi について昇順」,すなわち「 bi について降順」に並べるのが最善となる.
後はこの順にソートしてシミュレーションすれば OK.
実装例
提出 #8218670 - AtCoder Regular Contest 053
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
#include <iostream>
#include <algorithm>
#include <vector>
using lint = long long;
int main() {
int n;
std::cin >> n;
std::vector<std::pair<lint, lint>> ps(n);
for (auto& p : ps) {
std::cin >> p.first >> p.second;
}
std::sort(ps.begin(), ps.end(),
[](auto a, auto b) {
bool aneg = a.first < a.second,
bneg = b.first < b.second;
if (aneg != bneg) {
return aneg > bneg;
} else if (aneg) {
return a.first < b.first;
} else {
return a.second > b.second;
}
});
lint ans = 0, sum = 0;
for (auto p : ps) {
sum += p.first;
ans = std::max(ans, sum);
sum -= p.second;
}
std::cout << ans << std::endl;
return 0;
}
|