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));
}
