코딩테스트/기타

[Java] 백준 1019번 : 책 페이지

sujin7837 2022. 4. 13. 10:10
반응형

문제

지민이는 전체 페이지의 수가 N인 책이 하나 있다. 첫 페이지는 1 페이지이고, 마지막 페이지는 N 페이지이다. 각 숫자가 전체 페이지 번호에서 모두 몇 번 나오는지 구해보자.

입력

첫째 줄에 N이 주어진다. N은 1,000,000,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 0이 총 몇 번 나오는지, 1이 총 몇 번 나오는지, ..., 9가 총 몇 번 나오는지를 공백으로 구분해 출력한다.

예제 입력 1

11

예제 출력 1

1 4 1 1 1 1 1 1 1 1

예제 입력 2

7

예제 출력 2

0 1 1 1 1 1 1 1 0 0

예제 입력 3

19

예제 출력 3

1 12 2 2 2 2 2 2 2 2

예제 입력 4

999

예제 출력 4

189 300 300 300 300 300 300 300 300 300

예제 입력 5

543212345

예제 출력 5

429904664 541008121 540917467 540117067 533117017 473117011 429904664 429904664 429904664 429904664

 

소스코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

	private static BufferedReader br;
	private static StringTokenizer st;
	
	private static int N, cnt[];
	
	public static void main(String[] args) throws NumberFormatException, IOException {

		br=new BufferedReader(new InputStreamReader(System.in));
		N=Integer.parseInt(br.readLine());
		cnt=new int[10];
		
		long start=1;
		long end=N;
		long size=1;
		outer : while(start<=end) {
			while(start%10!=0) {	// 앞 남는 부분
				getRemain(start, size);
				start++;
				if(start>end) break outer;
			}
			
			while(end%10!=9) {	// 뒤 남는 부분
				getRemain(end, size);
				end--;
				if(start>end) break outer;
			}
			
			end/=10;
			start/=10;
			for(int i=0;i<10;i++) {	// 0~9 사이 
				cnt[i]+=(end-start+1)*size;
			}
			size*=10;
		}
		
		for(int i=0;i<10;i++) System.out.print(cnt[i]+" ");
	}

	private static void getRemain(long x, long size) {	// 남는 부분의 자릿수에 해당하는 숫자 개수 계산
		String s=String.valueOf(x);
		for(int i=0;i<s.length();i++) {
			cnt[s.charAt(i)-'0']+=size;
		}
	}
}

단순히 반복문만 이용하게 되면 시간 초과가 발생하므로 수학적으로 접근해야 하는 문제였습니다.

 

  1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 ...                
30 ...                
40 41 42 43            

N이 43인 경우를 살펴보면, 일의 자리의 수가 0~9인 구간은 10~39까지 존재합니다. 이것을 기준으로 앞 남는 부분과 뒤 남는 부분을 따로 계산하여 해당 구간의 계산값과 더해주면 결과를 얻을 수 있습니다.

 

1. 앞 남는 부분 : 나머지가 0이 나오기 전까지 현재 숫자를 1부터 1씩 증가시키며 getRemain을 통해 각 자리의 숫자의 개수를 더해줍니다.

2. 뒤 남는 부분 : 나머지가 9가 나오기 전까지 현재 숫자를 N부터 1씩 감소시키며 getRemain을 통해 각 자리의 숫자의 개수를 더해줍니다.

3. 0~9 구간 : 해당 숫자값을 10으로 나누고, 나머지를 size(10의 배수 단위)로 개수 저장해줍니다. -> 10으로 나눈 값이 0보다 큰 경우 해당 숫자값을 10으로 나누고, size 값을 10배하는 과정을 반복합니다.

4. 최종적으로 0~9에 저장된 숫자의 개수를 출력합니다.

반응형