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



정수 배열에 대해, 각 인덱스로 자신이 부분수열의 끝이고 길이가 L인 부분수열을 만들 수 있다.


각 부분수열의 최소값을 구해야 한다. (정수 배열의 길이 <= 오백만)



처음엔 세그먼트 트리 풀이만 생각이 났다. 근데 오백만이라 nlogn만 해도 오억이라 시간안에 풀 수 없었다.


복잡한 세그먼트 트리로만 헤매고 있었던 이유는,



각 부분수열의 최소값을 구할 때, 전 인덱스로 구한 최소값을 활용하는게 어려웠기 때문이다.


최소값이 부분수열의 맨 처음에 있었다면, 이번에 최소값을 구할 땐, 이전의 최소값은 구간에 포함이 안되고 새로 구해야 했다.


이러한 최악의 경우는 계속 일어날 수 있고(오름차순 정렬된 배열이라면), 좋은 풀이가 아니었다.



결국 이렇게 최악의 경우에서, 다음으로 작은 최소값을 알고 있으면 해결할 수 있다.


이 최소값도 다시 구간에서 벗어날 수 있으므로, 최소값들 후보를 죄다 갖고 있으면 된다!



이러한 자료구조를 고민하다가 덱을 쓰기로 했다.


덱의 맨 앞은 최소값을 가지고, 뒤로 갈수록 다음 최소값 후보들이 이어진다.



따라서 덱의 front에선 최소값들을 활용하고, 뒤로는 최소값 후보들을 집어넣으면 된다.


작업후에는 L-i ~ i 까지 최소값들 후보들이 덱에 들어가 있을 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <deque>
#include <algorithm>
using namespace std;
 
int n, l, a;
deque<pair<intint>> dq;
 
int main() {
    scanf("%d %d"&n, &l);
    for (int i = 0; i < n; ++i) {
        while (dq.size() && dq.front().second <= i - l)
            dq.pop_front();
 
        scanf("%d"&a);
        while (dq.size() && dq.back().first >= a)
            dq.pop_back();
 
        dq.push_back({ a,i });
        printf("%d ", dq.front().first);
    }
    return 0;
}
cs



뱀 게임을 하는데 사과의 위치와 뱀의 이동방법까지 주어진다. 언제 게임오버 되는지 구해보자.


뱀이 머리, 꼬리 이동과 몸에 박아버리는 경우를 어떻게 관리할지 아이디어만 있으면 후다닥 풀린다.


뱀처럼 덱을 만들어서(이중 연결 리스트) 머리에 머리좌표를 넣고, 꼬리에 꼬리좌표를 넣으면 상수시간에 이동이 구현된다.


사과를 먹고, 몸에 박는 경우는 평소처럼 맵에 표시만 하면 된다.



방향이 현재 방향 기준으로 왼쪽 오른쪽으로 주어지는 터라, 현재 방향을 저장하면서,


모듈러 연산을 통해 나침반 돌아가는 것마냥 관리해주면 편하다.


대부분의 뱅뱅 도는 문제들에선 통용되는 아이디어다.



문제가 조금 불친절한데, x초에 c로 방향전환하라는 얘기는 이동 다하고 다음 이동에 c가 영향을 준다는 얘기다.


x가 같은 입력이 여러번 주어질수 도 있어서 방향 전환 정보를 한 번 보고 말게 아니다.


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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <stdio.h>
#include <deque>
#include <vector>
using namespace std;
 
typedef pair<intint> pp;
deque<pp> bam;
vector<pp> cd;
pp cur;
 
int n, k, l, a, b, x, curd;
char c;
int map[100][100];
int dir[4][2= { {0,1},{1,0},{0,-1},{-1,0} };
 
int main() {
    scanf("%d %d"&n, &k);
    for (int i = 0; i < k; ++i) {
        scanf("%d %d"&a, &b);
        map[a - 1][b - 1= 1;
    }
    scanf("%d"&l);
 
    for (int i = 0; i < l; ++i) {
        scanf("%d %c"&a, &c);
        if (c == 'L')
            b = 3;
        else
            b = 1;
        cd.push_back({ a,b });
    }
 
    int cdi = 0, t = 0;
    bam.push_front({ 0,0 });
    map[0][0= 2;
 
    while(1) {
        t++;
        int xx = cur.first + dir[curd][0];
        int yy = cur.second + dir[curd][1];
 
        if (xx < 0 || xx >= n || yy < 0 || yy >= n)
            break;
        if (map[xx][yy] == 2)
            break;
 
        bam.push_front({ xx,yy });
        cur = { xx,yy };
        if (map[xx][yy] != 1) {
            map[bam.back().first][bam.back().second] = 0;
            bam.pop_back();
        }
        map[xx][yy] = 2;
 
        while (cdi < cd.size() && t == cd[cdi].first)
            curd = (curd + cd[cdi++].second) % 4;
    }
    
    printf("%d", t);
 
    return 0;
}
cs


2048 (Easy)



2048 게임을 하는데 5번 이동에 제일 큰 블록을 만들어야 한다.


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


블록이 어떻게 주어질지 모르니까 전략이 없다. 모든 경우를 실험해보자.


같은 상태에 도달하면 다시 할 필요가 없긴 하지만, 같은 상태를 확인하기도, 도달하기도 어렵다.


걍 백트래킹으로 조져보자.



백트래킹 함수는 다음과 같이 구성했다.


상단엔 5번 이동했는지 확인한다. 5번이면 가장 큰 블록을 찾아 답과 비교하고 종료시킨다.


5번 이하의 경우에 완전탐색을 수행해야 하는데,


이전 상태를 저장 -> 재귀호출 -> 복귀 와 같은 아주 간단한 구조로 되어있다.


아래 코드는 매우 더러우니 안 보는 것을 추천합니다..

4방향의 규칙을 다 하드코딩으로 해놓았기 때문에 가독성이 구리다.

포문으로 임시변수 가로줄에 옮기고, 합치고, 되돌려주면 되긴 하는데 시간에 쫓겨 그냥 다 해버렸다 ^오^


아이디어만 얻어가시면 되는데,

한 줄씩 블록을 합치는 것과, 진짜 블록만 스택에 넣고 다시 줄을 채우는 것으로 병합을 구현했다.


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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <stdio.h>
#include <stack>
using namespace std;
 
int n, ans;
int map[20][20];
 
void save(int tmap[][20]) {
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            tmap[i][j] = map[i][j];
}
 
void restore(int tmap[][20]) {
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            map[i][j] = tmap[i][j];
}
 
void backtracking(int cnt) {
    if (cnt == 5) {
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j)
                if (ans < map[i][j])
                    ans = map[i][j];
 
        return;
    }
 
    stack<int> st;
    int tmap[20][20];
    save(tmap);
 
    for (int i = 0; i < n; ++i) { //우
        for (int j = 0; j < n; ++j) {
            if (map[i][j]) {
                st.push(map[i][j]);
                map[i][j] = 0;
            }
        }
 
        int b = n - 1;
        while (!st.empty()) {
            int t = st.top();
            st.pop();
 
            if (!map[i][b])
                map[i][b] = t;
            else if (t == map[i][b])
                map[i][b--*= 2;
            else
                map[i][--b] = t;
        }
    }
    backtracking(cnt + 1);
    restore(tmap);
 
    for (int i = 0; i < n; ++i) { //좌
        for (int j = n - 1; j >= 0--j) {
            if (map[i][j]) {
                st.push(map[i][j]);
                map[i][j] = 0;
            }
        }
 
        int b = 0;
        while (!st.empty()) {
            int t = st.top();
            st.pop();
 
            if (!map[i][b])
                map[i][b] = t;
            else if (t == map[i][b])
                map[i][b++*= 2;
            else
                map[i][++b] = t;
        }
    }
    backtracking(cnt + 1);
    restore(tmap);
 
    for (int j = 0; j < n; ++j) { //위
        for (int i = 0; i < n; ++i) {
            if (map[i][j]) {
                st.push(map[i][j]);
                map[i][j] = 0;
            }
        }
 
        int b = n - 1;
        while (!st.empty()) {
            int t = st.top();
            st.pop();
 
            if (!map[b][j])
                map[b][j] = t;
            else if (t == map[b][j])
                map[b--][j] *= 2;
            else
                map[--b][j] = t;
        }
    }
    backtracking(cnt + 1);
    restore(tmap);
 
    for (int j = 0; j < n; ++j) { //아래
        for (int i = n - 1; i >= 0--i) {
            if (map[i][j]) {
                st.push(map[i][j]);
                map[i][j] = 0;
            }
        }
 
        int b = 0;
        while (!st.empty()) {
            int t = st.top();
            st.pop();
 
            if (!map[b][j])
                map[b][j] = t;
            else if (t == map[b][j])
                map[b++][j] *= 2;
            else
                map[++b][j] = t;
        }
    }
    backtracking(cnt + 1);
    restore(tmap);
}
 
int main() {
    scanf("%d"&n);
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            scanf("%d"&map[i][j]);
 
    backtracking(0);
    printf("%d", ans);
 
    return 0;
}
cs


+ Recent posts