우선 3의 배수 여부를 어떻게 구할지 생각해보자. 주어진 숫자의 범위가 크므로 에라토스테네스의 체처럼 배열을 사용할 수 없다. 대신 3의 배수는 각 자리수의 합이 3으로 나누어 떨어지는 속성을 이용해 DP 를 사용할 수 있다.
i = 자리수
j = 가장 높은 자리의 수
for(int k = 0; k < 9; k++)
{
dp[i+1][j][0] += dp[j][k][(0 - j) MOD 3]
dp[i+1][j][1] += dp[j][k][(1 - j) MOD 3]
dp[i+1][j][2] += dp[j][k][(2 - j) MOD 3]
}
여기서 3/6/9 를 포함하는 경우를 제외시키는 것은 간단하다. 또한 각 자리수마다 숫자의 갯수는 일정하므로 여집합을 이용하면 3/6/9 가 포함되는 경우를 바로 구할 수 있다.
예를들어 dp[자리수][가장높은자리의 수][각 자리 수 합 MOD 3] = 인 경우의 수 에서 dp[1][1] 를 생각해보자. 1 로 시작하는 2자리 수 중에서 3이 들어가는 것을 뺀 10, 11, 12, 14, 15, 17, 18, 19 를 각 자리 수 합에 맞게 카운팅을 하면 1, 3, 3 이 된다. 전체 수는 10 개이므로 10 - 1 - 3 - 3 하면 3/6/9 가 포함되는 경우를 구할 수 있다.
이제 각 자리수마다 이를 이용해 계산하면 된다. 이때 틀리기 쉬운 부분이 a~b 범위에서 a 가 박수치는 수인 경우 따로 처리해줘야 한다는 점이다.
시간 복잡도
O(\(\mathrm{N}\))
코드
풀이 2
설명
풀이 1에서 최적화 할 부분이 하나 있다. 위 풀이에서 가장 높은 자리의 숫자가 다르더라도 MOD 3 이 같으면 dp 값이 같다. 그래서 dp[자리수-1][각 자리 수 합 MOD 3] = 인 경우의 수 로 두고 첫번째 자리의 숫자를 알면 기존과 같은 작업을 할 수 있다.
예를 들어 2자리 숫자이고 첫번째 자리의 수가 2 라면 dp[1][1] = 3 가 3/6/9 를 포함하지 않는 3의 배수의 갯수가 된다. 1자리 숫자이고 첫번째 자리 수가 3 이라면 dp[0][0] = 1 이 3/6/9 를 포함하지 않는 3의 배수의 갯수가 된다.
댓글남기기