[백준] 1038 감소하는수
똥꼬집 발동해서 수열로 하루종일 풀었던 문제..
import java.util.*;
import java.io.*;
public class Main{
// 다음 순열을 만들어주는 함수
public static boolean next_perm(int[] arr){
int i = arr.length -1;
while( i > 0 && arr[i-1] >= arr[i]){
i--;
}
if(i <= 0){
return false;
}
int j = arr.length -1;
while( arr[j] <= arr[i-1] ){
j--;
}
int temp = arr[j];
arr[j] = arr[i-1];
arr[i-1] = temp;
int k = arr.length -1;
while( i < k ){
temp = arr[k];
arr[k] = arr[i];
arr[i] = temp;
i++;
k--;
}
return true;
}
public static void main(String []args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
// 최대 10자리 숫자를 사용한 예(9876543210) 가 1022번째 이므로
// 1023번째 이상의 감소하는 수는 존재하지 않는다
if(n >= 1023){
System.out.println(-1);
return;
}
// 한자리 수는 그 자체로 감소하는 수
if( n < 10 ){
System.out.println(n);
return;
}
// 결국 감소하는 수라는건, 10개의 숫자 중 임의로 몇개만 선택하면
// 자동으로 감소하는 방향으로 배열된다고 생각하면 된다.
// 따라서 차례대로 10C0, 10C1, 10C2 ... , 10C10 을 쭉 누적합 해둔 수열이 필요하다.
int[] c = {0, 9, 54, 174, 384, 636, 846, 966, 1011, 1021, 1022};
// l에는 입력받는 n이 c에서 속하는 구간(인덱스) 를 저장할 변수다
int l = -1;
for(int i = 1 ; i < c.length ; i++ ){
if(n <= c[i]){
l = i; // 처음으로 자기보다 큰 원소를 만났을때 빠져나온다. 예 : 18입력시 i = 2일때 빠져나옴
break;
}
}
// l은 즉 숫자의 자릿수를 의미한다.
// 위의 예로 계속해보면, l=2이므로 18번째 감소수는 두자리 숫자다.
// idx에는 18번째 감소수가 두자리 숫자 그룹내에서 몇번째에 속하는지를 저장한다.
int idx = n - c[l-1];
// num은 선택될 숫자를 1과 0으로 표시할 배열
int[] num = new int[10];
// l이 2일 때에는 0000000011로 초기화 되어야 한다
for(int i = 9 ; i >= 10-l ; i--){
num[i] = 1;
}
int cnt = 1;
// 이제 본격적으로 순열을 돌려가며 해당 위치를 찾는다.
do{
if( cnt == idx ){
StringBuilder sb = new StringBuilder();
for(int i = 0 ; i < 10 ; i++ ){
if(num[i] == 1){
sb.append(9-i); // num에서 0번째 원소는 9의 유무를 나타내므로 이렇게 바꿔줘야함
}
}
System.out.println(sb);
break;
}
cnt++;
}while(next_perm(num));
}
}
Comments