문제

 

풀이

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

이 문제와 같은 풀이입니다.

 

엘리스는 강림제에 참여한 신도들이 T명 이상 모여야 지상에 강림한다고 합니다.

만약 신도들이 T명 미만으로 모였을 때 친구를 최대 K명까지 초대하여 T명을 맞출 수도 있습니다.

친구들은 친구들을 제외한 신도들이 T명 이상이 되었다면 모두 탈출한다고 하여 적절한 시기에만 친구를 불러야 합니다.

 

저는 dp로 문제에 접근했고, 우선 누적합을 통해 참여하는 신도들의 수를 시간별로 구합니다.

범위로 누적합을 구해야하기 때문에 imos 기법을 활용했습니다.

imos 기법으로 범위의 양 끝지점에만 카운팅을 먼저 하고, 마지막에 한번에 누적합을 구할 수 있습니다.

 

dp[N][K][pre]: N 시간에 친구 K명을 부를 수 있고, 이미 참여중인 친구가 pre명일 때 엘리스가 지상으로 강림하는 최대 시간

문제에서 나올 수 있는 경우는 4가지입니다.

1. 신도들만 T명 이상 모였을 경우

2. 신도 + 이미 참여중인 친구들이 T명 이상 모였을 경우

3. 친구들을 더 추가하여 T명을 채울 수 있는 경우

4. 친구들을 추가해도 T명을 채우지 못하는 경우

 

1번의 경우는 엘리스가 강림할 수 있으므로 +1을 하고 다음 시간을 확인합니다.

이미 참여중인 친구들이 있다면 모두 탈출하기 때문에 pre는 0으로 맞춥니다.

 

2번의 경우도 엘리스가 강림할 수 있으므로 +1을 하고 다음 시간을 확인합니다.

친구들을 제외한 시도들이 T보다 적으므로 pre도 그대로 유지합니다.

 

3번의 경우도 엘리스가 강림할 수 있으므로 +1을 하고 다음 시간을 확인합니다.

친구를 tmp명 더 추가합니다. pre는 pre + tmp가 되겠고, k에서도 tmp만큼 빼줍니다.

 

4번의 경우는 엘리스가 강림할 수 없으므로 바로 다음 시간을 확인합니다.

이때 친구들을 더 추가하지 않으며, 이미 참여중인 친구들은 계속 참여하기 때문에 pre를 그대로 유지합니다.

 

코드

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
#include <iostream>
#include <cstring>
#include <algorithm>
#define MAX 310
using namespace std;
 
int sum[MAX];
int dp[MAX][MAX][MAX];
int N, M, K, T;
 
int solve(int idx, int k, int pre) {
    if (idx > N) return 0;
    int& ret = dp[idx][k][pre];
    if (ret != -1return ret;
 
    if (sum[idx] + pre >= T) {
        int next = pre;
        if (sum[idx] >= T) next = 0;
        return ret = solve(idx + 1, k, next) + 1;
    }
 
    ret = solve(idx + 1, k, pre);
    int tmp = T - sum[idx] - pre;
    if (k && k >= tmp) {
        ret = max(ret, solve(idx + 1, k - tmp, pre + tmp) + 1);
    }
    return ret;
}
 
void init() {
    memset(dp, -1sizeof(dp));
    for (int i = 1; i < MAX; i++) {
        sum[i] += sum[i - 1];
    }
}
 
void func() {
    init();
    cout << solve(1, K, 0<< '\n';
}
 
void input() {
    int l, r;
    cin >> N >> M >> K >> T;
    while (M--) {
        cin >> l >> r;
        sum[l]++;
        sum[r]--;
    }
}
 
int main() {
    cin.tie(NULL); cout.tie(NULL);
    ios::sync_with_stdio(false);
 
    input();
    func();
 
    return 0;
}
cs

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 3114 사과와 바나나  (0) 2024.06.13
boj 11560 다항식 게임  (0) 2024.06.13
boj 12841 정보대 등산  (0) 2023.07.31
boj 25427 DKSH를 찾아라  (0) 2023.05.21
boj 25682 체스판 다시 칠하기 2  (0) 2023.02.26

+ Recent posts