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

 

28018번: 시간이 겹칠까?

댓글을 달아준 학생 수 $N$이 주어진다. $(1\leq N\leq 100\,000)$ 다음 $N$개 줄에는 각 학생의 좌석 배정 시각 $S$와 종료 시각 $E$가 주어진다. $(1\leq S\leq E\leq 1\,000\,000)$ 다음 줄에는 특정한 시각의 개수

www.acmicpc.net

특정 시간에 학생이 몇명 채워져 있는지 구하는 문제입니다.

이 문제는 학생들이 머무르는 구간 l ~ r이 주어집니다.

l ~ r 구간을 모두 채워주어야 하며, 매 쿼리의 l ~ r 구간의 누적을 구하면 O(N^2)의 시간이 걸려 TLE가 발생합니다.

매 쿼리마다 누적합을 갱신하지 않고, 시작과 끝에만 표시하여 한꺼번에 누적합을 구할 수 있는 imos 기법을 활용합니다.

 

학생은 l 시간에 들어와서 r 시간까지 머무릅니다.

따라서 학생이 존재하기 시작하는 l 시간에 +1, 학생이 없는 시간인 r + 1 시간에 -1을 누적합니다.

마지막에 누적합을 갱신하면 O(N) 시간 만으로도 문제를 해결할 수 있습니다.

 

 

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
#include <iostream>
#define MAX 1000001
using namespace std;
 
int dp[MAX];
int N, M;
 
void func() {
    for (int i = 1; i < MAX; i++) {
        dp[i] += dp[i - 1];
    }
 
    int x;
    cin >> M;
    while (M--) {
        cin >> x;
        cout << dp[x] << '\n';
    }
}
 
void input() {
    int l, r;
    cin >> N;
    for (int i = 1; i <= N; i++) {
        cin >> l >> r;
        dp[l]++;
        dp[r + 1]--;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 12841 정보대 등산  (0) 2023.07.31
boj 25427 DKSH를 찾아라  (0) 2023.05.21
boj 25682 체스판 다시 칠하기 2  (0) 2023.02.26
boj 12996 Acka  (0) 2023.01.29
boj 14450 Hoof, Paper, Scissors (Gold)  (0) 2022.12.30

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

 

12841번: 정보대 등산

숭실 대학교 정보 과학관은 숭실 대학교 건물 중 제일 높은 곳에 있다. 민주는 평소에 버스를 타고 이 언덕을 오르지만, 이 문제에 등장하기 위하여 오늘 하루만 걸어서 올라간다. 정보 과학관을

www.acmicpc.net

출발 지점은 왼쪽, 도착 지점은 오른쪽에 있으므로 무조건 횡단보도를 건너야 합니다. 

문제에서는 1번만 횡단보도를 건널 수 있다고 제한하고 있습니다.

그렇게 되면 계산은 간단해집니다.

왼쪽 길로 가다가 횡단보도를 건너고 나머지는 오른쪽 길로만 간다는 뜻이 됩니다.

 

여기서 누적 합을 떠올릴 수 있습니다.

왼쪽, 오른쪽 길의 누적합을 각각 구합니다.

아래 코드에서는 i + 1번 지점까지의 거리를 dp[i]로 저장하고 있습니다.

따라서 i번 지점에서 횡단보도를 건너려면 dp[i - 1] 까지만 계산하면 됩니다.

dp[i - 1].first + cross[i]: 왼쪽에서 i번 지점까지 이동 후 횡단보도를 건넜을 때의 길이가 됩니다.

 

횡단보도를 건넜으니 이제 오른쪽 길에 위치해 있습니다.

따라서 N번 지점까지 그냥 가기만 하면 됩니다. (+ dp[N - 1].second - dp[i - 1].second)

 

거리가 같으면 번호가 낮은 지점을 출력해야 한다는 점만 주의하셔서 최소를 갱신해주시면 됩니다.

 

 

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
#include <iostream>
#define MAX 100001
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
 
pii dp[MAX];
ll cross[MAX];
int N;
 
void func() {
    int idx = 0;
    ll ret = 1e12;
    for (int i = 1; i <= N; i++) {
        ll sum = cross[i] + dp[i - 1].first + dp[N - 1].second - dp[i - 1].second;
        if (ret > sum) {
            idx = i;
            ret = sum;
        }
    }
 
    cout << idx << ' ' << ret << '\n';
}
 
void input() {
    cin >> N;
    for (int i = 1; i <= N; i++) {
        cin >> cross[i];
    }
 
    for (int i = 1; i < N; i++) {
        cin >> dp[i].first;
        dp[i].first += dp[i - 1].first;
    }
 
    for (int i = 1; i < N; i++) {
        cin >> dp[i].second;
        dp[i].second += dp[i - 1].second;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 28018 시간이 겹칠까?  (0) 2023.08.08
boj 25427 DKSH를 찾아라  (0) 2023.05.21
boj 25682 체스판 다시 칠하기 2  (0) 2023.02.26
boj 12996 Acka  (0) 2023.01.29
boj 14450 Hoof, Paper, Scissors (Gold)  (0) 2022.12.30

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

 

25682번: 체스판 다시 칠하기 2

첫째 줄에 정수 N, M, K가 주어진다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

www.acmicpc.net

2차원 배열 내 누적합 문제입니다.

2차원 누적합은 (sx, sy) ~ (ex, ey)의 누적합을 말하며, dp[i][j] = cur + dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] 공식을 활용해야 합니다.

 

체스판은 검은색, 흰색이 번갈아 칠해져있어야 하고, (1, 1) 지점의 색은 정해지지 않았습니다.

따라서 (1, 1) 지점에 검은색이 올 경우와 흰색이 올 경우를 모두 구해서 최솟값을 구해야 합니다.

이를 위해 dp를 두개 사용합니다.

 

좌표의 x, y값을 더한 값이 홀수인 좌표들끼리와 짝수인 좌표들끼리의 색은 같습니다.

이를 활용하여 해당 좌표에 색이 바껴야하는지에 대해서 각각 누적합을 구할 수 있습니다.

dp를 채웠다면 K * K 크기의 정사각형의 누적합들을 순회하며 최솟값을 구하도록 합니다.

 

 

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
#include <iostream>
#include <algorithm>
#define MAX 2001
using namespace std;
 
char list[MAX][MAX];
int bdp[MAX][MAX], wdp[MAX][MAX];
int N, M, K;
 
void getPrefixSum() {
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            bdp[i][j] = bdp[i - 1][j] + bdp[i][j - 1- bdp[i - 1][j - 1];
            wdp[i][j] = wdp[i - 1][j] + wdp[i][j - 1- wdp[i - 1][j - 1];
 
            if (list[i][j] == 'W') {
                if ((i + j) % 2) {
                    wdp[i][j]++;
                }
                else {
                    bdp[i][j]++;
                }
            }
            else {
                if ((i + j) % 2) {
                    bdp[i][j]++;
                }
                else {
                    wdp[i][j]++;
                }
            }
        }
    }
}
 
void func() {
    getPrefixSum();
    int ret = 2147483647;
    for (int i = K; i <= N; i++) {
        for (int j = K; j <= M; j++) {
            ret = min(ret, bdp[i][j] - bdp[i - K][j] - bdp[i][j - K] + bdp[i - K][j - K]);
            ret = min(ret, wdp[i][j] - wdp[i - K][j] - wdp[i][j - K] + wdp[i - K][j - K]);
        }
    }
 
    cout << ret << '\n';
}
 
void input() {
    cin >> N >> M >> K;
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= M; j++) {
            cin >> list[i][j];
        }
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

'algorithm > dp' 카테고리의 다른 글

boj 12841 정보대 등산  (0) 2023.07.31
boj 25427 DKSH를 찾아라  (0) 2023.05.21
boj 12996 Acka  (0) 2023.01.29
boj 14450 Hoof, Paper, Scissors (Gold)  (0) 2022.12.30
boj 14453 Hoof, Paper, Scissors (Silver)  (0) 2022.12.30

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

N이 20만이므로 모든 부분합을 직접 구할 수는 없습니다.

기존의 누적합 문제에서 부분합을 구하는 식은 dp[r] - dp[l - 1] = K 입니다.

K는 입력으로 주어지기 때문에 식을 변형하면 dp[r] - K = dp[l - 1]이 되고, 이 식으로 문제에 접근합니다.

 

식을 풀어서 설명하면 dp[r](1 ~ r번 요소의 누적합) - K = dp[l - 1](1 ~ l - 1번 요소의 누적합)

이렇게 되는데, l - 1번을 구할 필요는 없습니다. dp[r] - K와 일치하는 값이 몇 번 나왔는지 세어주면 되는겁니다.

이를 계산하기 위해 map을 사용합니다. 정렬이 필요없으므로 unordred_map을 사용하였습니다.

 

누적합을 구하면서 dp[i] - K 값이 map에 있다면 map[dp[i] - K]만큼 카운트를 증가시킵니다.

그리고 dp[i] 값을 새롭게 map에 넣어주거나 1을 증가시킵니다.

dp[i] 값이 K인 경우는 ans를 따로 증가시켜야 합니다.

 

N = 200000, K = 0이고, 배열의 값이 모두 0이라면 int 범위를 넘으므로 long long을 사용해야 합니다.

 

 

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
#include <iostream>
#include <unordered_map>
#define MAX 200001
using namespace std;
typedef long long ll;
 
int dp[MAX];
int N, K;
 
void func() {
    unordered_map<int, ll> m;
    ll ans = 0;
    for (int i = 1; i <= N; i++) {
        dp[i] += dp[i - 1];
        if (dp[i] == K) ans++;
 
        if (m.find(dp[i] - K) != m.end()) {
            ans += m[dp[i] - K];
        }
 
        if (m.find(dp[i]) != m.end()) {
            m[dp[i]]++;
        }
        else {
           m.insert({ dp[i], 1LL });
        }
    }
 
    cout << ans << '\n';
}
 
void input() {
    cin >> N >> K;
    for (int i = 1; i <= N; i++) {
        cin >> dp[i];
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

 

'algorithm > dp' 카테고리의 다른 글

boj 14453 Hoof, Paper, Scissors (Silver)  (0) 2022.12.30
boj 2281 데스노트  (1) 2022.10.08
boj 21923 곡예 비행  (0) 2022.06.10
boj 12978 스크루지 민호 2  (0) 2022.06.08
boj 10986 나머지 합  (0) 2022.03.08

+ Recent posts