[백준 1038] 감소하는 수

문제 링크

https://www.acmicpc.net/problem/1038

풀이

과연 감수하는 수가 N의 상한인 106개나 있을 수 있을까요? 제일 큰 감소하는 수는 9876543210이고 이보다 작은 감소하는 수는 그리 많아 보이진 않습니다. 감소하는 수의 개수를 아무리 높게 잡는다고 해도 최대 105개라고 생각할 수 있고 이는 O(NlogN)이 충분히 통과할 만한 제한입니다. 모든 감소하는 수를 우선순위 큐에 넣고 작은 순서대로 뽑아낼 수 있지 않을까요? 처음 우선순위 큐에는 [1,9]구간 내의 수를 넣습니다. 우선순위 큐에 N번째 감소하는 수가 들어있지 않으면 우선순위 큐에 들어있는 가장 작은 수 u[0,u%101]사이에 있는 숫자를 뒤에 붙여서 다시 우선순위 큐에 넣습니다. 이를 반복하다 보면 N번째 감소하는 수가 나오거나 우선순위 큐가 비어서 N번째 감소하는 수는 존재하지 않음을 알 수 있습니다.

추가로 우선순위 큐에 들어오는 수를 보면 수가 증가하는 순서대로 들어오기 때문에 우선순위 큐 대신 일반 큐를 이용한 구현이 가능합니다. 아래 코드는 큐를 이용한 구현입니다. 큐에 들어오는 수의 개수는 최대 N개 이므로 시간복잡도는 O(N)입니다.

전체 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int n;
queue<ll> q;

int main(){
    scanf("%d",&n);
    if(n == 0) return !printf("0");

    for(int i=1;i<=9;i++) q.push(i);
    while(!q.empty() && --n){
        ll u = q.front(); q.pop();
        for(int i=0;i<u%10;i++) q.push(u*10 + i);
    }
    printf("%lld",q.empty() ? -1 : q.front());
}

여담

98765432101022번째 감소하는 수입니다.