페이지

2291번: Sequence

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


$O(nm)$

dp[n][m]를 항이 n개이고 합이 m인 본 수열의 개수라고 정의하면
dp[0][0]=1
dp[i][j]=dp[i][j-i]+dp[i-1][j-1]

수열은 대응관계를 이용해서 앞자리부터 복원합니다.

f(n,m,k): 항이 n개이고 합이 m인 k번째 수열
이 함수가 호출되었다고 합시다.
a[1]=1을 가정했을 때의 수열 개수가 k보다 크거나 같은 경우(k<=dp[n-1][m-1]) a[1]=1이라는 것을 알 수 있습니다.
수열의 다음 항들은 다음과 같이 적절히 대응시킬 수 있습니다.
f(n,m,k) = {a[1]=1, a[2...n]=f(n-1,m-1,k)}
a[1]=x를 가정했을 때의 수열 개수가 k보다 작은 경우(k>dp[n-1][m-1]) a[1]이 더 커져야 함을 알 수 있습니다.
a[1]=x+1인 수열과 a[1]=x인 수열은 다음과 같이 적절히 대응시킬 수 있습니다.
곧 f(n, m, k) = f(n, m-n, k-dp[n-1][m-1])인 수열의 각 자리에 1씩 더한 수열

이러한 재귀적인 성질은 아래와 같은 간단한 반목문(8~11번째 줄)을 통해 구현할 수 있습니다.


#include<cstdio>
int dp[11][221] = { 1 }, n, m, k;
int main() {
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= n; i++)
        for (int j = i; j <= m; j++)
            dp[i][j] = dp[i][j - i] + dp[i - 1][j - 1];
    for (int i = 1; n--, m--;) {
        for (; k > dp[n][m]; i++) k -= dp[n][m], m -= n + 1;
        printf("%d ", i);
    }
    return 0;
}

댓글 4개 :

  1. 안녕하세요~ 요즘 백준 풀어보는 도중에 안풀리는 문제가 2291번이었거든요~
    이거 푸신거같은데, 이해가 안되는 데 설명 좀 해주실수있나요...?
    ( 아, 그리고 본 수열이 그냥 수열 말씀하시는 건가요~?)

    답글삭제
  2. 점화식에 대해서는 '자연수의 분할'을 찾아보세요.
    수열을 결정하는 부분을 모르신다면 다시 달아주세요.

    답글삭제
  3. 안녕하세요 정말 글 많은 도움되고 있습니다.
    다름이아니오라 이번글을 보다가
    그 밑에 수열을 정하는 부분에서 막혀서 이해를 하려고하였으나
    저 수열의 k번째의 기준을 어떻게 잡는지가 궁금합니다.

    위에 구현해둔 dy테이블은 문제처럼 중복수를 제외하지 않은
    단지 dy[2][4]일경우 2자리로 합이 4인수를 만드는 테이블이니
    1 3
    2 2
    3 1
    3이라는 경우의 수가 나와 an-1 <= an 조건이 적용되지 않는테이블이라
    K번째의 수열을 찾는방법이 이해가 잘 가지 않습니다 부가적으로 설명 해주실수있는지요?
    dy[n-pos][sum-(n-pos)*(num-1)-num]의 도출과정이 이해가가지 않습니다.

    답글삭제
  4. 처음 구한 테이블은 자연수의 분할 개수 즉, 문제처럼 중복수를 제외한 개수가 맞습니다.
    소스는 옛날거라 갈아엎었습니다.
    부연설명을 달아놓긴 했지만 능력부족으로 잘 전달될지는 모르겠습니다;; 안풀리면 다시 질문해주세요.

    답글삭제