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

 

5430번: AC

각 테스트 케이스에 대해서, 입력으로 주어진 정수 배열에 함수를 수행한 결과를 출력한다. 만약, 에러가 발생한 경우에는 error를 출력한다.

www.acmicpc.net


풀이 과정

배열에 R(뒤집기), D(첫 번째 수 버리기) 연산을 합쳐서 10만 번 이하로 시행할 때, 배열의 최종 결과를 구하는 문제이다.

 

배열을 뒤집는 연산은 O(N)이고, 첫 번째 수를 버리는 연산도 O(N)이다. 배열이 아닌 큐를 사용하면 첫번째 수를 버리는 연산을 pop()으로 O(1)만에 수행할 수 있으니 큐로 문제를 풀면 좋을 것 같다는 생각이 든다.

 

그런데 R을 인식했을 때 실제로 배열을 뒤집으면 시간 초과가 발생한다. 배열에 들어있는 수가 문제에서 주어진 최대 값인 10만 개가 주어졌다고 가정하고, 수행할 함수 p가 길이가 10만이라고 해보자. p가 전부 다 R로 꽉 차있어도 실제로 10만 번 뒤집을 필요까지는 없다. R이 2번 연속으로 나오면 아무 연산을 안 해도 2번 뒤집은 것이랑 같은 결과를 내기 때문이다.

 

따라서 RDRDRDRDRDRD..... RDRDRDRD 이런 식으로 나와서 R이 50000번 나오는 경우가 가장 시간이 오래 걸리는 경우일 것이다. 10만 크기의 배열을 5만 번 뒤집을 때 연산 횟수를 어림잡아 계산하면 10만 * 5만 = 50억인데, 시간제한 1초 내에 50억 번의 연산을 할 수는 없다.

 

R이 짝수번 연속으로 나올 때 연산을 무시해서 연산 횟수를 줄여도 시간 내에 문제를 해결할 수 없으니 이 문제를 시간 내에 해결하려면 뒤집기 연산이 나왔을 때 배열을 실제로 뒤집으면 안 된다.

 

배열이 뒤집힌 상태에서 첫 번째 수 버리기 연산을 하는 것은 배열의 마지막 수를 버리는 연산과 같다. 또한 배열이 뒤집힌 상태이면 배열을 역순으로 출력하고, 뒤집히지 않은 상태일 때 그대로 출력한다면 배열을 뒤집지 않고도 첫 번째 수 버리기 연산과 배열의 출력이 이루어 질 것이다.

 

따라서 배열이 뒤집혔는지를 판단하는 변수 하나를 두고, 변수의 값에 따라 첫번째 수를 버릴지, 마지막 수를 버릴지, 똑바로 출력할지, 반대로 출력할지를 판단해서 문제를 해결할 수 있다. 첫번째 수, 마지막 수를 O(1)로 버릴 수 있는 자료구조는 덱이므로 덱을 사용해서 문제를 해결하였다.


소스 코드

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

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;

    while(T--) {
        deque<int> DQ;
        int t = 0;
        bool errorFlag = false;

        string s;
        cin >> s;

        int num;
        cin >> num;

        string numbers;
        cin >> numbers;


        // 문자열 파싱후 덱에 삽입
        int parse_number = 0;
        for (char let : numbers) {
            if (isdigit(let)) {
                int parse = int(let) - 48;
                parse_number = parse_number * 10 + parse;
            } else {
                if (parse_number == 0) continue;
                DQ.push_back(parse_number);
                parse_number = 0;
            }
        }


        for (char let : s) {
            if (let == 'R') {
                t = (t+1) & 1;
            } else if (let == 'D') {
                if (DQ.empty()) {
                    cout << "error\n";
                    errorFlag = true;
                    break;
                }

                if (t == 0) {
                    DQ.pop_front();
                } else {
                    DQ.pop_back();
                }
            }
        }

        if (errorFlag) continue;

        cout << '[';
        int save_size = DQ.size();

        for (int i = 1; i <= save_size; i++) {
            if (t == 0) {
                cout << DQ.front();
                DQ.pop_front();
            } else {
                cout << DQ.back();
                DQ.pop_back();
            }
            if (i == save_size) break;
            cout << ',';
        }

        cout << "]\n";
    }

    return 0;
}

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

백준 7576 - 토마토 [C++]  (0) 2022.08.01
백준 2504 - 괄호의 값 [C++]  (0) 2022.07.31
백준 1021 - 회전하는 큐 [C++]  (0) 2022.07.30
백준 2493 - 탑 [C++]  (0) 2022.07.30
백준 5397 - 키로거 [C++]  (0) 2022.07.27

+ Recent posts