Post

BOJ 15486 퇴사 2

BOJ 15486 퇴사 2

문제

오늘부터 $N$일 동안 가질 수 있는 최대 상담 수익을 구하기. 각 날짜 $i$마다 상담에 걸리는 시간 $T_i$와 받을 수 있는 금액 $P_i$가 주어집니다.

상담을 시작하면 $T_i$일 동안은 다른 상담을 할 수 없습니다.

상담은 반드시 $N+1$일이 되기 전(즉, $N$일 이내)에 마쳐야 수익을 받을 수 있습니다.

  • $N$의 범위: $1 \le N \le 1,500,000$
  • $T_i$의 범위: $1 \le T_i \le 50$
  • $P_i$의 범위: $1 \le P_i \le 1,000$

복잡도 분석

Time Complexity: $O(N)$. 전체 날짜 $N$을 단 한 번 순회하므로 $1.5 \times 10^6$ 연산 내에 해결 가능합니다.

Space Complexity: $O(N)$. dp, T, P 배열을 위해 약 $18\text{MB}$의 메모리를 사용하며, 이는 제한 사항(512MB)을 충분히 만족합니다.

접근법

가중치가 있는 구간 스케줄링 문제.

dp[i]를 “$i$번째 날에 상담이 완료되어 얻을 수 있는 최대 수익”으로 정의.

모든 날에 상담이 딱 맞춰 끝나지 않으므로, 루프를 돌며 max_p = max(max_p, dp[i])를 통해 “오늘 상담을 시작하기 전까지 벌 수 있는 최대 수익”을 계속 갱신하며 들고 갑니다.

\[dp[i + T_i] = \max(dp[i + T_i], max\_p + P_i)\]

풀이

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
38
39
40
#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;

const int INF = 1e9;
const ll LINF = 1e18;
const int MOD = 998244353; // or 1e9 + 7

#define rep(i, a, b) for (int i = (a); i < (b); ++i)
#define all(x) (x).begin(), (x).end()

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    vector<int> T;
    vector<int> P;
    int N; cin>>N;
    rep(i,0,N){
        int a,b; cin>>a>>b;
        T.push_back(a); P.push_back(b);
    }
    
    vector<int> dp(N+1);
    int max_p = 0;
    rep(i,0,N){
        max_p = max(max_p, dp[i]);
        if (i+T[i] < N+1){
            dp[i+T[i]] = max(dp[i+T[i]], max_p + P[i]);
        }
    }
    max_p = max(max_p, dp[N]);

    cout << max_p;

    return 0;
}
This post is licensed under CC BY 4.0 by the author.