알고리즘/문제 풀이

11501번: 주식

Themion 2022. 1. 6. 15:34

https://www.acmicpc.net/problem/11501

 

11501번: 주식

입력의 첫 줄에는 테스트케이스 수를 나타내는 자연수 T가 주어진다. 각 테스트케이스 별로 첫 줄에는 날의 수를 나타내는 자연수 N(2 ≤ N ≤ 1,000,000)이 주어지고, 둘째 줄에는 날 별 주가를 나타

www.acmicpc.net

0번째 날부터 N - 1번쨰 날 중 주식의 가격이 p번째 날에 가장 크다고 하자. 0번째 날부터 p - 1번째 날까지는 주식을 산 뒤, p번째 날에 주식을 팔면 0번째 날부터 p번째 날까지 최대 이득을 볼 수 있다. 이제 p + 1번째 날부터 N - 1번째 날 중 주식의 가격이 q번째 날에 가장 크다면, 다시 p + 1번째 날부터 q - 1번째 날까지는 주식을 산 뒤, q번째 날에 팔면 p + 1번째 날부터 q번째 날까지 최대 이익을 볼 수 있다.

이 과정을 각 최댓값 별로 구역을 나눠 모든 구역에 대해 실행하면 최대 이익을 볼 수 있다. 단 최댓값을 구하는 데에 O(N) 시간이 걸리므로, 최악의 경우 각 테스트 케이스마다 O(N ^ 2)시간이 걸리게 된다. 따라서 0번째 날부터 시작하는 것이 아니라 N - 1번째 날부터 시작해 현재 날의 가격이 최대라면 최댓값을 갱신하고, 그렇지 않다면 최댓값에서 현재 가격을 뺀 값만큼 이득을 보았다고 간주해 계산하면 각 테스트 케이스마다 O(N) 시간 안에 답을 구할 수 있다.

#include <iostream>

using namespace std;

typedef long long ll;

#define MAX_N 1000000

// 각 테스트 케이스를 입력받아 정답을 반환
ll test_case() {
    // 주가 배열의 길이
    int N;
    // val[i]: i번째 날의 주가, max: 팔았을 때 최대 이익을 볼 수 있는 주가
    short val[MAX_N] = { 0, }, max = 0;
    // ret: 실현손익
    ll ret = 0;

    // 주가 배열을 입력받은 뒤
    cin >> N;
    for (int i = 0; i < N; i++) cin >> val[i];
    // 마지막 날부터 역순으로
    for (int i = N - 1; i >= 0; i--) {
        // 주가의 최대치를 발견한다면 매도일을 i번째 날로 지정
        if (max < val[i]) max = val[i];
        // 그렇지 않다면 주식을 사 지정한 매도일에 주식을 매도
        else ret += max - val[i];
    }

    // 실현손익을 반환
    return ret;
}

int main() {
    // 입출력 속도 향상
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    
    int T;
    // 테스트 케이스의 수를 입력받고 각 테스트 케이스의 정답을 출력
    for (cin >> T; T--; ) cout << test_case() << '\n';
    return 0;
}

'알고리즘 > 문제 풀이' 카테고리의 다른 글

11650번: 좌표 정렬하기  (0) 2022.01.06
11568번: 민균이의 계략  (0) 2022.01.06
11444번: 피보나치 수 6  (0) 2022.01.06
11437번: LCA  (0) 2022.01.05
11404번: 플로이드  (0) 2022.01.05