본문 바로가기
ps

[백준] 2281 - 데스노트

by kariskan 2023. 8. 1.

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

 

2281번: 데스노트

첫째 줄에 n(1 ≤ n ≤ 1,000), m(1 ≤ m ≤ 1,000)이 주어진다. m은 노트의 가로 칸의 개수(폭, 너비)이다. 다음 n개의 줄에는 각 사람의 이름의 길이가 노트에 적어야 할 순서대로 주어진다. 각 길이는 m

www.acmicpc.net

 

처음에 이분 탐색으로 해결하려고 했다가, 이분 탐색의 조건에 맞지 않아서 실패했고, 다음으로 다이나믹 프로그래밍으로 시도했다.

dp로 풀기 위해서 배열을 다음과 같이 정의했다.

dp[i] = i번째 사람의 이름까지 적었을 때, 제곱의 합의 최소

 

이렇게 되면 점화식은 굉장히 간단해진다. i 이전에 모든 경우의 수를 찾아서, 어디서 줄을 바꿀 건지만 결정하면 된다.

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= i; j++) {
        if (sum[i] - sum[j - 1] + i - j > m) {
            continue;
        }
        int c = dp[j - 1] + (m - (sum[i] - sum[j - 1] + i - j)) * (m - (sum[i] - sum[j - 1] + i - j));
        if (dp[i] == -1 || dp[i] > c) {
            dp[i] = c;
        }
    }
}

 

그런데 답을 구하는 과정에서, 제일 마지막 줄은 계산하지 않는다라고 한다.

이 부분을 위해서 한 번만 배열을 더 훑어서 마지막 줄이 가능한 위치에서의 최솟값을 구하면 된다.

 

#include <iostream>
#include <cstring>
using namespace std;

int n, m, a[1001], sum[1001], dp[1001];

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        sum[i] = sum[i - 1] + a[i];
    }
    memset(dp, -1, sizeof(dp));
    dp[0] = 0;
    dp[1] = (m - a[1]) * (m - a[1]);
    int ans = 2000000000;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            if (sum[i] - sum[j - 1] + i - j > m) {
                continue;
            }
            int c = dp[j - 1] + (m - (sum[i] - sum[j - 1] + i - j)) *
                                    (m - (sum[i] - sum[j - 1] + i - j));
            if (dp[i] == -1 || dp[i] > c) {
                dp[i] = c;
            }
        }
    }
    
    for (int i = 1; i <= n; i++) {
        if (sum[n] - sum[i] + n - i <= m) {
            ans = min(ans, dp[i]);
        }
    }
    cout << ans;
}

'ps' 카테고리의 다른 글

[백준] 3117 - YouTube  (0) 2023.08.02
[백준] 21922 - 학부 연구생 민상  (0) 2023.08.02
[백준] 17828 - 문자열 화폐  (0) 2023.08.01
[백준] 2878 - 캔디캔디  (0) 2023.08.01
[백준] 2463 - 비용  (0) 2023.07.27

댓글