반응형

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

 

20924번: 트리의 기둥과 가지

첫 번째 줄에는 노드의 개수 $N$($1 \le N \le 200\,000$)과 루트 노드의 번호 $R$($1 \le R \le N$)이 주어진다. 이후 $N-1$개의 줄에 세 개의 정수 $a$, $b$, $d$($1 \le a, b \le N$, $ a \ne b$)가 주어진다. 이는 $a$번

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. 그래프를 입력받고, list 배열에 저장합니다.

 

2. dfs를 이용하여 루트부터 탐색하면서 현재 노드까지의 길이를 저장하고, 그중 가장 긴 길이를 all에 저장합니다.

 

3. 자식 노드가 2개 이상인 노드의 길이 중 가장 짧은 길이를 gidung에 저장합니다.

 

4. gidung 과 all - gidung을 출력합니다.

 

[ 소스코드 ]

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
#include<iostream>
#include<vector>
 
using namespace std;
 
int N, R;
int a, b, d;
vector<pair<intint>> list[200001];
int visited[200001];
int all;
int gidung = 987654321;
 
void dfs(int node, int dist)
{
    int cnt = 0;
    all = max(all, dist);
    for (auto& next : list[node]) {
        if (visited[next.first] == 0) {
            cnt++;
            visited[next.first] = 1;
            dfs(next.first, dist + next.second);
            visited[next.first] = 0;
        }
    }
 
    if (cnt >= 2) {
        gidung = min(gidung, dist);
    }
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> N >> R;
 
    for (int i = 0; i < N - 1; i++) {
        int a, b, d;
        cin >> a >> b >> d;
 
        list[a].push_back({ b,d });
        list[b].push_back({ a,d });
    }
 
    visited[R] = 1;
    dfs(R, 0);
 
    if (gidung == 987654321) {
        gidung = all;
    }
 
    cout << gidung << ' ' << all - gidung;
}
cs
반응형
반응형

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

 

10835번: 카드게임

첫 줄에는 한 더미의 카드의 개수를 나타내는 자연수 N(1 ≤ N ≤ 2,000)이 주어진다. 다음 줄에는 왼쪽 더미의 카드에 적힌 정수 A(1 ≤ A ≤ 2,000)가 카드 순서대로 N개 주어진다. 그 다음 줄에는 오

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. dp[ 2000 ][ 2000 ] 배열을 선언하고 -1로 초기화해 줍니다.

 

2. 현재 카드더미가 왼쪽이 left번 째, 오른쪽이 right번 째일 때 점수의 최댓값을 dp [ left ][ right ]에 저장합니다.

 

3. 왼쪽 카드만 버릴 때와 왼쪽 카드와 오른쪽 카드를 동시에 버릴 때는 점수를 얻지 못하고, 왼쪽 카드보다 오른쪽 카드의 숫자가 작을 때 오른쪽 카드만 버릴 수 있고, 오른쪽 카드만 버렸을 때 점수를 얻을 수 있으므로 다음과 같은 점화식을 통해 최댓값을 구합니다.

 

ret = max(dfs(left + 1, right), dfs(left + 1, right + 1));


if (l[ left ] > r[ right ]) {
ret = max(ret, dfs(left, right + 1) + r[ right ]);
}

 

4. dp[ 0 ][ 0 ]을 출력합니다.

 

[ 소스코드 ]

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
#include<iostream>
 
using namespace std;
 
int N;
int dp[2000][2000];
int l[2000];
int r[2000];
int ans;
 
int dfs(int left, int right)
{
    if (left == N || right == N) return 0;
    if (dp[left][right] != -1return dp[left][right];
 
    int& ret = dp[left][right];
    ret = 0;
    
    ret = max(dfs(left + 1, right), dfs(left + 1, right + 1));
 
    if (l[left] > r[right]) {
        ret = max(ret, dfs(left, right + 1+ r[right]);
    }
 
    return ret;
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> N;
 
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            dp[i][j] = -1;
        }
    }
 
    for (int i = 0; i < N; i++) {
        cin >> l[i];
    }
 
    for (int i = 0; i < N; i++) {
        cin >> r[i];
    }
 
    cout << dfs(00);
}
cs
반응형
반응형

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

 

3197번: 백조의 호수

입력의 첫째 줄에는 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1500. 다음 R개의 줄에는 각각 길이 C의 문자열이 하나씩 주어진다. '.'은 물 공간, 'X'는 빙판 공간, 'L'은 백조가 있는 공간으로 나타낸다.

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. 현재 호수의 상태를 저장할 queue<pair<int, int>> water, 다음 호수의 상태를 저장할 queue<pair<int, int>> tmpW, 현재 백조의 위치를 저장할 queue<pair<int, int>> swan, 마지막으로 다음 백조의 위치를 저장할 queue<pair<int, int>> tmpS를 선언합니다.

 

2. 호수를 입력받으면서 얼음이 아닌 좌표를 water에 push 하고, 백조 한 마리의 위치를 swan에 push 합니다.

 

3. 먼저 백조가 만날 수 있는지 bfs를 통해 움직이고, 벽에 마주칠 때마다 다음에 갈 수 있는 위치이므로 tmpS에 push 하고, 백조를 만난다면 Find 변수를 true로 갱신합니다.

 

4. 빙하가 녹으면서 현재 물에 맞닿아 있다면 tmpW에 push 해줍니다.

 

5. Find 변수가 true라면 ans를 출력해 주고, 그렇지 않다면 water = tmpW, swan = tmpS로 갱신해 주고, ans++를 해줍니다.

 

[ 소스코드 ]

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
#include<iostream>
#include<queue>
 
using namespace std;
 
int R, C;
int r, c;
char arr[1500][1501];
int visited[1500][1500];
int dr[] = { -1,1,0,0 };
int dc[] = { 0,0,-1,1 };
queue<pair<intint>> swan, water, tmpW, tmpS;
bool Find = false;
 
void BFSwater()
{
    while (!water.empty()) {
        const int r = water.front().first;
        const int c = water.front().second;
        water.pop();
 
        for (int i = 0; i < 4; i++) {
            const int rr = r + dr[i];
            const int cc = c + dc[i];
 
            if (rr >= 0 && rr < R && cc >= 0 && cc < C) {
                if (arr[rr][cc] == 'X') {
                    tmpW.push({ rr,cc });
                    arr[rr][cc] = '.';
                }
            }
        }
    }
}
 
void BFSswan()
{
    while (!swan.empty() && Find == false) {
        const int r = swan.front().first;
        const int c = swan.front().second;
        swan.pop();
 
        for (int i = 0; i < 4; i++) {
            const int rr = r + dr[i];
            const int cc = c + dc[i];
 
            if (rr >= 0 && rr < R && cc >= 0 && cc < C && visited[rr][cc] == 0) {
                visited[rr][cc] = 1;
                if (arr[rr][cc] == '.') {
                    swan.push({ rr,cc });
                }
                else if (arr[rr][cc] == 'X') {
                    tmpS.push({ rr,cc });
                    arr[rr][cc] = '.';
                }
                else if (arr[rr][cc] == 'L') {
                    Find = true;
                    break;
                }
            }
        }
    }
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> R >> C;
 
    
 
    for (int i = 0; i < R; i++) {
        cin >> arr[i];
        for (int j = 0; j < C; j++) {
            if (arr[i][j] != 'X') {
                water.push({ i,j });
            }
            if (arr[i][j] == 'L') {
                r = i;
                c = j;
            }
        }
    }
 
    swan.push({ r,c });
    visited[r][c] = 1;
 
    int ans = 0;
 
    while (1) {
        BFSswan();
        if (Find == true) {
            cout << ans;
            return 0;
        }
        BFSwater();
        ans++;
 
        water = tmpW;
        swan = tmpS;
 
        tmpW = queue<pair<intint>>();
        tmpS = queue<pair<intint>>();
    }
}
cs
반응형
반응형

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

 

2015번: 수들의 합 4

첫째 줄에 정수 N과 K가 주어진다. (1 ≤ N ≤ 200,000, |K| ≤ 2,000,000,000) N과 K 사이에는 빈칸이 하나 있다. 둘째 줄에는 배열 A를 이루는 N개의 정수가 빈 칸을 사이에 두고 A[1], A[2], ..., A[N]의 순서로

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. 배열의 1번부터 N번까지 수를 입력받으면서 누적합을 arr 배열에 저장하고, unordered_map<int, long long> um 자료구조에 누적합의 개수를 저장합니다.

 

2. ans에 um[ arr[ i ] - K ] 의 개수를 더해줍니다.

 

3. ans를 출력합니다.

 

[ 소스코드 ]

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
#include<iostream>
#include<unordered_map>
#define ll long long
 
using namespace std;
 
int N, K;
int arr[200001];
unordered_map<int, ll> um;
ll ans;
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> N >> K;
 
    um[0= 1;
 
    for (int i = 1; i <= N; i++) {
        cin >> arr[i];
        arr[i] += arr[i - 1];
 
        ans += um[arr[i] - K];
 
        um[arr[i]]++;
    }
 
    cout << ans;
}
cs
반응형
반응형

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

 

13565번: 침투

첫째 줄에는 격자의 크기를 나타내는  M (2 ≤ M ≤ 1,000) 과 N (2 ≤ N ≤ 1,000) 이 주어진다. M줄에 걸쳐서, N개의 0 또는 1 이 공백 없이 주어진다. 0은 전류가 잘 통하는 흰색, 1은 전류가 통하지 않

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. 격자를 입력받고, 격자의 y 좌표가 0인 좌표의 arr 값이 '0'이라면 queue에 넣고, visited 배열을 만들어 방문 여부를 저장합니다.

 

2. bfs를 이용하여 arr의 값이 '0'인 좌표로만 이동하면서 y 좌표의 값이 M이상인 경우가 있다면 YES를, 그렇지 않다면 NO를 출력합니다.

 

[ 소스코드 ]

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
#include<iostream>
#include<queue>
 
using namespace std;
 
int M, N;
char arr[1000][1001];
int visited[1000][1000];
int dy[] = { -1,1,0,0 };
int dx[] = { 0,0,-1,1 };
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> M >> N;
 
    for (int i = 0; i < M; i++) {
        cin >> arr[i];
    }
 
    queue<pair<intint>> q;
 
    for (int i = 0; i < N; i++) {
        if (arr[0][i] == '0') {
            q.push({ 0,i });
            visited[0][i] = 1;
        }
    }
 
    while (!q.empty()) {
        const int y = q.front().first;
        const int x = q.front().second;
        q.pop();
 
        for (int i = 0; i < 4; i++) {
            const int yy = y + dy[i];
            const int xx = x + dx[i];
 
            if (yy >= 0 && yy < M && xx >= 0 && xx < N) {
                if (visited[yy][xx] == 0 && arr[yy][xx] == '0') {
                    visited[yy][xx] = 1;
                    q.push({ yy,xx });
                }
            }
            else if (yy == M) {
                cout << "YES";
                return 0;
            }
        }
    }
 
    cout << "NO";
}
cs
반응형
반응형

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

 

12761번: 돌다리

동규와 주미는 일직선 상의 돌 다리 위에있다. 돌의 번호는 0 부터 100,000 까지 존재하고 동규는 \(N\)번 돌 위에, 주미는 \(M\)번 돌 위에 위치하고 있다. 동규는 주미가 너무 보고싶기 때문에 최대

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. A, B, N, M을 입력받고, visited 배열을 만들어 방문 여부를 저장합니다.

 

2. bfs를 이용하여 8가지 경우의 수를 통해 이동하면서 cnt값을 올려주고, 현재 위치가 M이라면 cnt 값을 출력하고 종료합니다.

[ 소스코드 ]

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
#include<iostream>
#include<queue>
 
using namespace std;
 
int A, B, N, M;
int visited[100001];
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> A >> B >> N >> M;
 
    queue<pair<intint>>q;
    q.push({ N,0 });
 
    visited[N] = 1;
 
    while (!q.empty()) {
        const int cur = q.front().first;
        const int cnt = q.front().second;
        q.pop();
 
        if (cur == M) {
            cout << cnt;
            return 0;
        }
 
        if (cur < M) {
            if (cur + 1 <= 100000 && visited[cur + 1== 0) {
                visited[cur + 1= 1;
                q.push({ cur + 1,cnt + 1 });
            }
 
            if (cur + A <= 100000 && visited[cur + A] == 0) {
                visited[cur + A] = 1;
                q.push({ cur + A,cnt + 1 });
            }
 
            if (cur + B <= 100000 && visited[cur + B] == 0) {
                visited[cur + B] = 1;
                q.push({ cur + B,cnt + 1 });
            }
 
            if (cur * A <= 100000 && visited[cur * A] == 0) {
                visited[cur * A] = 1;
                q.push({ cur * A,cnt + 1 });
            }
 
            if (cur * B <= 100000 && visited[cur * B] == 0) {
                visited[cur * B] = 1;
                q.push({ cur * B,cnt + 1 });
            }
        }
 
        if (cur - 1 >= 0 && visited[cur - 1== 0) {
            visited[cur - 1= 1;
            q.push({ cur - 1,cnt + 1 });
        }
 
        if (cur - A >= 0 && visited[cur - A] == 0) {
            visited[cur - A] = 1;
            q.push({ cur - A,cnt + 1 });
        }
 
        if (cur - B >= 0 && visited[cur - B] == 0) {
            visited[cur - B] = 1;
            q.push({ cur - B,cnt + 1 });
        }
    }
}
cs
반응형
반응형

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

 

12016번: 라운드 로빈 스케줄러

첫째 줄에 작업의 개수 N (1 ≤ N ≤ 100,000)이 주어진다. 둘째에는 각 작업을 수행해야하는 시간이 공백으로 구분되어 주어진다. 각 작업을 수행해야하는 시간은 1보다 크거나 같고, 1,000,000,000보다

www.acmicpc.net

 

 

[ 문제풀이 ]

이 문제를 풀기 전에 다음 글을 먼저 읽고 오시는 것을 추천드립니다.

https://rudalsd.tistory.com/364

 

[ 자료구조 ] 비재귀 세그먼트 트리 (Segment Tree)

1. 비재귀 세그먼트 트리 (Segment Tree) 재귀 세그먼트 트리에서는 항상 루트노드부터 시작했었습니다. 하지만 비재귀 세그먼트 트리에서는 반대로 리프노드부터 시작합니다. 2. 비재귀 세그먼트

rudalsd.tistory.com

 

1. 작업의 각 번호의 값을 1로 대입해 Segment Tree를 채웁니다.

 

2. 작업 수행 시간을 입력받고, 작업 수행 시간을 기준으로 오름차순으로, 작업의 번호를 기준으로 내림차순으로 정렬합니다.

 

3. 현재까지 작업한 작업의 개수를 Cur에 저장하고, 현재 같은 작업수를 가진 작업들의 수를 cnt, 현재 같은 작업수를 가진 작업들과 이전의 같은 작업수를 가진 작업들과의 차를 cur에 저장하고, 현재 남아있는 작업의 개수를 Cnt에 저장합니다.

 

4. 이전 작업의 수행 시간과 현재 작업의 수행 시간이 같다면 cnt++를 수행하고, 해당 작업 번호의 segment tree 노드의 값을 -1 해주고, ans[ arr[ i ].second ] = Cur + getTree(N, N + arr[ i ].second - 1) + cur * Cnt 의 식을 이용하여 ans배열을 채웁니다.

 

5. 이전 작업의 수행 시간과 현재 작업의 수행 시간이 다르다면

Cur += Cnt * (cur + 1);
Cnt -= cnt;
cnt = 0;
cur = arr[ i ].first - arr[ i - 1 ].first - 1;
temp = arr[ i ].first;
i--;

를 수행해줍니다.

 

6. ans를 출력해 줍니다.

 

[ 소스코드 ]

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
#include<iostream>
#include<algorithm>
#define ll long long
 
using namespace std;
 
int N;
int segTree[200000];
pair<intint> arr[100001];
ll ans[100001];
 
bool cmp(pair<intint> left, pair<intint> right)
{
    if (left.first == right.first) return left.second > right.second;
    return left.first < right.first;
}
 
void updateTree(int idx, int diff)
{
    while (idx) {
        segTree[idx] += diff;
        idx >>= 1;
    }
}
 
int getTree(int l, int r)
{
    int ret = 0;
 
    while (l <= r) {
        if (l & 1) {
            ret += segTree[l];
            l++;
        }
        if (~r & 1) {
            ret += segTree[r];
            r--;
        }
 
        l >>= 1;
        r >>= 1;
    }
 
    return ret;
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> N;
 
    for (int i = 1; i <= N; i++) {
        updateTree(N + i - 11);
        cin >> arr[i].first;
        arr[i].second = i;
    }
 
    sort(arr + 1, arr + N + 1, cmp);
 
    int temp = arr[1].first;
    int cnt = 0;
    int Cnt = N;
    int cur = arr[1].first - 1;
    ll Cur = 0;
 
    for (int i = 1; i <= N; i++) {
        if (temp == arr[i].first) {
            cnt++;
            ans[arr[i].second] = Cur + (ll)getTree(N, N + arr[i].second - 1+ 1LL * cur * Cnt;
            updateTree(N + arr[i].second - 1-1);
        }
        else {
            Cur += 1LL * Cnt * (1LL * cur + 1);
            Cnt -= cnt;
            cnt = 0;
            cur = arr[i].first - arr[i - 1].first - 1;
            temp = arr[i].first;
            i--;
        }
    }
 
    for (int i = 1; i <= N; i++) {
        cout << ans[i] << '\n';
    }
}
cs
반응형
반응형

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

 

17609번: 회문

각 문자열이 회문인지, 유사 회문인지, 둘 모두 해당되지 않는지를 판단하여 회문이면 0, 유사 회문이면 1, 둘 모두 아니면 2를 순서대로 한 줄에 하나씩 출력한다.

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. 문자열을 입력받아 str 변수에 저장합니다.

 

2. s = 0, e = str.size() - 1에서 시작하여 s < e 일 때까지 투포인터를 활용하여 단어가 같다면 s++, e--, 단어가 다르다면 erase flag를 통해 지운 지 지우지 않았는지를 체크하고, s++일 때와 e--일 때를 총 두 번 구해줍니다.

 

3. 만약 erase == false, ans == true라면 0을, erase == true, ans == true라면 1을, 둘 다 아니라면 2를 출력합니다.

 

[ 소스코드 ]

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
#include<iostream>
#include<string>
 
using namespace std;
 
int T;
bool erase;
 
bool check(string str, int num)
{
    int s = 0, e = str.size() - 1;
 
    while (s < e) {
        if (str[s] == str[e]) {
            s++;
            e--;
        }
        else {
            if (!erase) {
                if (num == 1) {
                    if (str[s + 1== str[e]) {
                        s++;
                        erase = true;
                    }
                }
                else {
                    if (str[s] == str[e - 1]) {
                        e--;
                        erase = true;
                    }
                }
                if (!erase) {
                    return false;
                }
            }
            else {
                return false;
            }
        }
    }
    return true;
}
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> T;
 
    while (T--) {
        erase = false;
        string str;
        cin >> str;
 
        erase = false;
 
        if (check(str, 1)) {
            if (erase) {
                cout << 1;
            }
            else {
                cout << 0;
            }
            cout << '\n';
            continue;
        }
 
        erase = false;
 
        if (check(str, 2)) {
            if (erase) {
                cout << 1;
            }
            else {
                cout << 0;
            }
            cout << '\n';
            continue;
        }
 
        cout << 2;
        cout << '\n';
    }
}
cs
반응형
반응형

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

 

5569번: 출근 경로

상근이가 사는 도시는 남북 방향으로 도로가 w개, 동서 방향으로 도로가 h개 있다.  남북 방향 도로는 서쪽부터 순서대로 번호가 1, 2, ..., w로 매겨져 있다. 또, 동서 방향 도로는 남쪽부터 순서대

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. dp[h][w][dir][turn] 배열을 만들어 해당 좌표에 해당 방향으로 방향을 바꿨는지 여부를 따져 도착할 수 있는 경우의 수를 저장합니다. (dir : 0 - 가로, 1 - 세로)

 

2. 다음과 같은 점화식을 이용하여 dp 배열을 채웁니다.

dp[ i ][ j ][ 0 ][ 0 ] = (dp[ i ][ j - 1 ][ 0 ][ 1 ] + dp[ i ][ j - 1 ][ 0 ][ 0 ]) % M;
dp[ i ][ j ][ 0 ][ 1 ] = dp[ i ][ j - 1 ][ 1 ][ 0 ] % M;
dp[ i ][ j ][ 1 ][ 0 ] = (dp[ i - 1 ][ j ][ 1 ][ 1 ] + dp[ i - 1 ][ j ][ 1 ][ 0 ]) % M;
dp[ i ][ j ][ 1 ][ 1 ] = dp[ i - 1 ][ j ][ 0 ][ 0 ] % M;

 

3. (dp[ h ][ w ][ 0 ][ 0 ] + dp[ h ][ w ][ 0 ][ 1 ] + dp[ h ][ w ][ 1 ][ 0 ] + dp[ h ][ w ][ 1 ][ 1 ]) % M 의 값을 출력합니다.

 

[ 소스코드 ]

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
#include<iostream>
#define M 100000
 
using namespace std;
 
int dp[101][101][2][2]; // h, w, dir, turn
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    int w, h;
    cin >> w >> h;
 
    for (int i = 2; i <= w; i++) {
        dp[1][i][0][0= 1;
    }
 
    for (int i = 2; i <= h; i++) {
        dp[i][1][1][0= 1;
    }
 
    for (int i = 2; i <= h; i++) {
        for (int j = 2; j <= w; j++) {
            dp[i][j][0][0= (dp[i][j - 1][0][1+ dp[i][j - 1][0][0]) % M;
            dp[i][j][0][1= dp[i][j - 1][1][0] % M;
            dp[i][j][1][0= (dp[i - 1][j][1][1+ dp[i - 1][j][1][0]) % M;
            dp[i][j][1][1= dp[i - 1][j][0][0] % M;
        }
    }
 
    int ans = 0;
 
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            ans += dp[h][w][i][j];
        }
    }
 
    cout << ans % M;
}
cs
반응형
반응형

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

 

13398번: 연속합 2

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어지고 둘째 줄에는 n개의 정수로 이루어진 수열이 주어진다. 수는 -1,000보다 크거나 같고, 1,000보다 작거나 같은 정수이다.

www.acmicpc.net

 

 

[ 문제풀이 ]

 

1. 수열을 입력받고, arr 배열에 저장합니다.

 

2. 다음과 같은 점화식을 이용하여 dp 배열을 채웁니다.

dp[ i ][ 0 ] = max( dp[ i - 1 ][ 0 ] + arr[ i ], arr[ i ] )

do[ i ][ 1 ] = max( dp[ i - 1 ][ 0 ], dp[ i - 1 ][ i ]+arr[ i ] )

 

3. 이 때, dp[ i ][ 1 ]은 해당 수를 지웠을 때의 최댓값입니다.

 

4. 모든 dp 배열의 값 중 가장 큰 값을 출력합니다. 

 

[ 소스코드 ]

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
#include<iostream>
 
using namespace std;
 
int n;
int arr[100000];
int dp[100000][2];
 
int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> n;
 
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }
 
    dp[0][0= arr[0];
 
    int ans = arr[0];
 
    for (int i = 1; i < n; i++) {
        dp[i][0= max(dp[i - 1][0+ arr[i], arr[i]);
        dp[i][1= max(dp[i - 1][1+ arr[i], dp[i - 1][0]);
        ans = max(max(ans, dp[i][0]), dp[i][1]);
    }
 
    cout << ans;
}
cs
반응형

+ Recent posts