Up

BOJ 2410:: 2의 멱수의 합

$n$의 제한이 1,000,000인데, 219 < 1,000,000 < 220이므로 1, 2, 4, …, 219으로 $n$을 나타내는 방법의 수를 물어보는 것과 동일합니다. $m$을 아래와 같이 정의합시다.

\[ m[i][j] = 1,2,4,\cdots,2^j\text{으로 } i\text{를 나타내는 방법의 수} \]

최종적으로 구해야 하는 건 $m[n][19]$입니다.

점화식을 생각해봅시다. 1, 2, 4, …, 2$j$으로 $n$을 나타낼 때 2$j$을 전혀 안 쓸 수도 있고 적어도 한 번 쓸 수도 있습니다. 따라서 다음 관게가 성립합니다.

\[ m[i][j] = m[i][j-1] + m[i-2^j][j] \]

단, $i$가 2$j$보다 작으면 $m[i][j] = m[i][j-1]$입니다. 또한 $i$가 0이면 방법의 수는 1가지이고 $j$가 0이면 1만 쓸 수 있으므로 방법의 수는 역시 1가지입니다.

#include<cstdio>

using namespace std;

int m[1000001][20];

int main(void) {
    int n;
    scanf("%d", &n);

    for (int i = 0; i < 20; i++)
        m[0][i] = 1;

    for (int i = 1; i <= n; i++) {
        m[i][0] = 1;
        for (int j = 1; j < 20; j++) {
            if (i >= (1 << j))
                m[i][j] = (m[i][j - 1] + m[i - (1 << j)][j]) % 1000000000;
            else
                m[i][j] = m[i][j - 1];
        }
    }

    printf("%d", m[n][19]);

    return 0;
}