1부터 N까지의 수를 이어서 쓰면 다음과 같이 새로운 하나의 수를 얻을 수 있다.
1234567891011121314151617181920212223...
이렇게 만들어진 새로운 수에서, 앞에서 k번째 자리 숫자가 어떤 숫자인지 구하는 프로그램을 작성하시오.
left
를 1, right
을 N
이라고 생각했을 때, mid
는 N/2
이다.mid
까지 나열한 문자열 길이 len
을 구하고 k
와 비교한다.len
이 k
보다 작다면 left
를 mid + 1
로 옮겨서 오른쪽 부분을 탐색한다.len
이 k
보다 크다면 right
을 mid - 1
로 옮겨서 왼쪽 부분을 탐색한다. 이때, 외부(ans
)에 mid
값을 기록해둔다. left
와 right
이 교차할 때까지 반복한다.ans
가 k번째 인덱스가 가리키는 수 임을 알 수 있다.ans
의 어떤 숫자를 가리키고 있는지 판단한다.ans
까지의 길이에서 k를 빼고 1을 더 빼주면 ans
의 몇 번 인덱스를 가리키는지 알 수 있다.#include <cstdio>
#include <cmath>
typedef unsigned long long ull;
// 정수 n의 자릿수를 구하는 함수
int getStand(int n) {
int ret = 0;
while (n > 0) n /= 10, ret++;
return ret;
}
// 정수 n까지 나열했을 때 문자열의 길이
// '수 이어 쓰기 1' 문제의 핵심 알고리즘
ull getLen(int n) {
int len = getStand(n);
ull ret = 0;
while (len > 0) {
int tmp = n - pow(10, len - 1) + 1;
ret += tmp * len;
n -= tmp;
len--;
}
return ret;
}
// 파라매트릭 서치
int solve(int n, int k) {
ull len = getLen(n);
if (len < k) return -1;
int l = 1, r = n, m, ans;
while (l <= r) {
m = (l + r) / 2;
len = getLen(m);
if (len < k) l = m + 1;
else ans = m, r = m - 1;
}
char buf[11];
int s = sprintf(buf, "%d", ans);
len = getLen(ans);
return buf[s - (len - k) - 1] - '0';
}
int main() {
int N, k;
scanf("%d %d", &N, &k);
printf("%d\n", solve(N, k));
}