BOJ[4375] - 1 by JavaScript
1
문제
언어
- JavaScript
문제 풀이 step 1
- 주어진 n 에 대해서 1 로만 이루어진 n 의 배수를 찾아야합니다.
- 예를 들어, n 이 3 이라면 1, 11, 111, 1111, … 이런 모양의 수 중에서 3 의 배수를 찾아야 합니다.
- 그렇다면 완전 탐색 기법으로 1, 11, 111, 1111, … 을 하나씩 다 나머지 연산을 통해 검사해보면 됩니다.
- 하지만 이렇게 하면 시간 초과가 발생합니다.
문제 풀이 step 2
- 완전 탐색 기법으로 할 경우 1 이 정말 많아질 수 있습니다. (ex. 1111111111111111…)
- 1 이 정말 많아지면 연산의 시간 복잡도는
O(수의 길이)가 됩니다. - 그래서 시간 초과가 발생하는 것입니다.
- 그렇다면 어떻게 해야할까요??
문제 풀이 step 3
- 시간 초과를 피하기 위해서 나머지 연산의 특성과 1 로만 이루어진 수의 특성을 이용해야 합니다.
- 나머지 연산은 다음과 같은 수식이 성립합니다.
(A + B) % M = A % M + B % M(A * B) % M = A % M * B % M
- 그리고 1 로만 이루어진 수들은 이런 성질을 가지고 있습니다.
1 = 111 = 1 * 10 + 1111 = 11 * 10 + 11111 = 111 * 10 + 1
- 우리가 구해야 할 것은 “각 수가 주어진 n 으로 나눴을 때 나머지가 0 인가” 입니다.
- 위의 두 성질을 이용하면 다음과 같은 식을 만들 수 있습니다. (n 이 3 이라면)
1 = 111 % 3 = ((1 % 3 * 10 % 3) + 1 % 3) % 3111 % 3 = ((11 % 3 * 10 % 3) + 1 % 3) % 31111 % 3 = ((111 % 3 * 10 % 3) + 1 % 3) % 3
- 식을 잘 보면 위에서 계산한 식이 다음 식에 포함되어 있다는 것을 알 수 있습니다.
- 이를 통해서 수의 길이를 줄여가며 검사해서 시간 초과를 피할 수 있습니다.
- 추가 설명은 주석에 작성하겠습니다.
소스 코드
const input = require("fs")
.readFileSync("/dev/stdin")
.toString()
.trim()
.split("\n");
const solution = (input) => {
let res = "";
for (let i = 0; i < input.length; i++) {
const n = parseInt(input[i]);
let cnt = 1;
let num = 1;
while (true) {
// 나머지 연산의 특성 덕분에 나머지 연산 후에도 다음 식에서 사용 가능
num %= n;
if (num === 0) break;
// 1111... 의 성질을 이용한 수식
num = num * 10 + 1;
cnt += 1;
}
res += cnt + "\n";
}
return res;
};
console.log(solution(input));