Official

B - 旅行の所持金 / Travel Budget Editorial by MMNMM Editorial for printing


旅行が始まる前の高橋君の所持金が \(0\) 円であるときの、\(i\) 日目までの処理がすべて終わった直後の所持金を \(D _ i\) とします \((1\le i\le N)\)。 すると、旅行が始まる前の高橋君の所持金 \(X\) に対して、\(i\) 日目までの処理がすべて終わった直後の所持金は \(X+D _ i\) となります。

問題文中の条件はすべての \(i\) に対して \(X+D _ i\ge0\) であることでした。 これは以下のように変形することができます。\[\begin{aligned}&\bigwedge _ {1\le i\le N}\bigl(X+D _ i\ge0\bigr)\\\iff&\min _ {1\le i\le N}\lbrace X+D _ i\rbrace\ge0\\\iff&X+\min _ {1\le i\le N}D _ i\ge0\\\iff&X\ge-\min _ {1\le i\le N}D _ i=\max _ {1\le i\le N}\lbrace-D _ i\rbrace\end{aligned}\]

よって、求めるものは \(\displaystyle X\ge\max _ {1\le i\le N}\lbrace-D _ i\rbrace\) を満たす \(0\) 以上の整数 \(X\) の最小値です。 制約から各 \(D _ i\) は整数であることがわかるので、これは \(\displaystyle \max\Bigl\lbrace 0,\max _ {1\le i\le N}\lbrace-D _ i\rbrace\Bigr\rbrace\) となり、これを計算することでこの問題を解くことができます。

各 \(D _ i\) は、高橋君の所持金をシミュレートすることで \(O(N)\) 時間で求めることができます。

実装例は以下のようになります。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int N;
    cin >> N;

    long ans = 0;
    long D = 0; // はじめの所持金を 0 円としてシミュレーションする
    for (int i = 0; i < N; ++i) {
        int A, B;
        cin >> A >> B;
        D += A; // A 円増やして
        D -= B; // B 円減らす
        ans = max(ans, -D); // 各 -D (と 0) の最大値が答え
    }

    cout << ans << endl;
    return 0;
}
N = int(input())

ans = 0
D = 0 # はじめの所持金を 0 円としてシミュレーションする

for i in range(N):
    A, B = map(int, input().split())
    D += A # A 円増やして
    D -= B # B 円減らす
    ans = max(ans, -D) # 各 -D (と 0) の最大値が答え

print(ans)

posted:
last update: