γ€ŒβŒ¨οΈα΄„s」PS/λ°±μ€€_μˆ˜ν•™&κ΅¬ν˜„

[Baekjoon/λ°±μ€€][1009][C/C++] λΆ„μ‚°μ²˜λ¦¬

λ£¨λ°€π•ƒπ•¦π•„π•šπ•£ 2023. 1. 17. 00:12
728x90
λ°˜μ‘ν˜•
γ€Žλͺ©μ°¨γ€
0. κ°œμš”

1. 문제
2. 풀이
3. μ½”λ“œ

0. κ°œμš”

κ°„λ‹¨ν•˜κ²Œ 풀릴 쀄 μ•Œκ³  호기둭게 ν’€μ–΄λ‚˜κ°”μ§€λ§Œ, 생각보닀 μ‹œκ°„μ΄ 걸렸던 λ¬Έμ œμ΄λ‹€. μ˜€λžœλ§Œμ— 문제 풀이λ₯Ό ν•΄μ„œ κ·ΈλŸ°κ°€ λ‡Œκ°€ κ΅³μ–΄μžˆλŠ” λŠλ‚Œ. 이 문제의 μΉ΄ν…Œκ³ λ¦¬λŠ” 'μˆ˜ν•™'κ³Ό 'κ΅¬ν˜„'이닀. '같은 수λ₯Ό λ¬΄ν•œνžˆ κ³±ν•΄λ‚˜κ°ˆ μ‹œ, 일의 μžλ¦¬λŠ” μ΅œλŒ€ 4주기둜 같은 μˆ˜κ°€ λ°˜λ³΅λœλ‹€'λΌλŠ” μˆ˜ν•™μ  원리λ₯Ό κΉ¨λ‹¬μœΌλ©΄ λ¬Έμ œλŠ” μ‰½κ²Œ ν’€λ¦°λ‹€. 

1. 문제

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

 

1009번: λΆ„μ‚°μ²˜λ¦¬

μž…λ ₯의 첫 μ€„μ—λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ 개수 Tκ°€ 주어진닀. κ·Έ λ‹€μŒ 쀄뢀터 각각의 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ— λŒ€ν•΄ μ •μˆ˜ a와 bκ°€ 주어진닀. (1 ≤ a < 100, 1 ≤ b < 1,000,000)

www.acmicpc.net

[문제]

μž¬μš©μ΄λŠ” μ΅œμ‹  컴퓨터 10λŒ€λ₯Ό 가지고 μžˆλ‹€. μ–΄λŠ λ‚  μž¬μš©μ΄λŠ” λ§Žμ€ 데이터λ₯Ό μ²˜λ¦¬ν•΄μ•Ό 될 일이 μƒκ²¨μ„œ 각 컴퓨터에 1λ²ˆλΆ€ν„° 10λ²ˆκΉŒμ§€μ˜ 번호λ₯Ό λΆ€μ—¬ν•˜κ³ , 10λŒ€μ˜ 컴퓨터가 λ‹€μŒκ³Ό 같은 λ°©λ²•μœΌλ‘œ 데이터듀을 μ²˜λ¦¬ν•˜κΈ°λ‘œ ν•˜μ˜€λ‹€.

1번 λ°μ΄ν„°λŠ” 1번 컴퓨터, 2번 λ°μ΄ν„°λŠ” 2번 컴퓨터, 3번 λ°μ΄ν„°λŠ” 3번 컴퓨터, ... ,

10번 λ°μ΄ν„°λŠ” 10번 컴퓨터, 11번 λ°μ΄ν„°λŠ” 1번 컴퓨터, 12번 λ°μ΄ν„°λŠ” 2번 컴퓨터, ...

총 λ°μ΄ν„°μ˜ κ°œμˆ˜λŠ” 항상 ab개의 ν˜•νƒœλ‘œ 주어진닀. μž¬μš©μ΄λŠ” 문득 λ§ˆμ§€λ§‰ 데이터가 처리될 μ»΄ν“¨ν„°μ˜ λ²ˆν˜Έκ°€ κΆκΈˆν•΄μ‘Œλ‹€. 이λ₯Ό μˆ˜ν–‰ν•΄ μ£ΌλŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜λΌ.

[μž…λ ₯]

μž…λ ₯의 첫 μ€„μ—λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ 개수 Tκ°€ 주어진닀. κ·Έλ‹€μŒ 쀄뢀터 각각의 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ— λŒ€ν•΄ μ •μˆ˜ a와 bκ°€ 주어진닀. (1 ≤ a < 100, 1 ≤ b < 1,000,000)

[좜λ ₯]

각 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ— λŒ€ν•΄ λ§ˆμ§€λ§‰ 데이터가 μ²˜λ¦¬λ˜λŠ” μ»΄ν“¨ν„°μ˜ 번호λ₯Ό 좜λ ₯ν•œλ‹€.

[예제 μž…λ ₯ 1]

5
1 6
3 7
6 2
7 100
9 635

[예제 좜λ ₯ 1]

1
7
6
1
9

2. 풀이

[문제 이해]

1번, 11번, 21번, 31번, ... ν•΄μ„œ 끝자리(=일의자리)κ°€ 1인 데이터듀은 1번 컴퓨터가 처리.

2번, 12번, 22번, 32번, ... ν•΄μ„œ 끝자리(=일의자리)κ°€ 2인 데이터듀은 2번 컴퓨터가 처리.

3번, 13번, 23번, 33번, ... ν•΄μ„œ 끝자리(=일의자리)κ°€ 3인 데이터듀은 3번 컴퓨터가 처리.

...

9번, 19번, 29번, 39번, ... ν•΄μ„œ 끝자리(=일의자리)κ°€ 9인 데이터듀은 9번 컴퓨터가 처리.

10번, 20번, 30번, 40번, ... ν•΄μ„œ 끝자리(=일의자리)κ°€ 0인 데이터듀은 10번 컴퓨터가 처리.

 

즉, λ°μ΄ν„°μ˜ 개수λ₯Ό μ•Œλ©΄, λ§ˆμ§€λ§‰μ— 처리될 λ°μ΄ν„°μ˜ 번호λ₯Ό μ•Œκ²Œ 되고, ν•΄λ‹Ή λ°μ΄ν„°μ˜ 끝자리(=일의자리)λ₯Ό μ•Œκ²Œ 되면, λͺ‡ 번 컴퓨터가 ν•΄λ‹Ή 데이터λ₯Ό μ²˜λ¦¬ν• μ§€ μ•Œκ²Œ λœλ‹€.

 

∴ μž…λ ₯λ°μ΄ν„°μ˜ 끝자리(=일의자리)λ₯Ό μ•Œμ•„λ‚΄λ©΄ λ¬Έμ œλŠ” ν’€λ¦¬κ²Œ λœλ‹€.

 

[μž…λ ₯ 데이터 ν˜•μ‹]

TλŠ” ν…Œμ΄μŠ€ μΌ€μ΄μŠ€μ˜ 개수. 즉, μž…λ ₯ λ°μ΄ν„°μ˜ κ°œμˆ˜μ΄λ‹€.

aλŠ” λ°‘.

bλŠ” μ§€μˆ˜.

 

∴ $a^b$κ°’μ˜ 끝자리(=일의자리)λ₯Ό μ•Œμ•„λ‚΄λ©΄ λœλ‹€.

 

[직관적인 풀이1] = μ˜€λ²„ν”Œλ‘œμš°(Overflow) λ°œμƒ.

(int)pow(a,b) % 10

λ‹¨μˆœν•˜κ²Œ, math.h  λΌμ΄λΈŒλŸ¬λ¦¬μ— μ‘΄μž¬ν•˜λŠ” pow() ν•¨μˆ˜λ₯Ό μ΄μš©ν•˜μ—¬ $a^b$값을 κ΅¬ν•˜κ³ , ν•΄λ‹Ήκ°’μ˜ 끝자리(=일의자리)λ₯Ό κ΅¬ν•˜λ©΄ μ–΄λ–¨κΉŒ? a의 μ΅œλŒ“κ°’μ€ 99, b의 μ΅œλŒ“κ°’μ€ 999,999 μ΄λ―€λ‘œ pow(99, 999999)의 값은 거의  $100^{10^6}$으둜 κ·Έ 값이 μ–΄λ§ˆλ¬΄μ‹œν•˜κ²Œ 컀진닀. μ΄λŠ” νŠΉμ • μžλ£Œν˜•μ΄ 감당할 수 μžˆλŠ” 크기의 데이터가 μ•„λ‹ˆλ―€λ‘œ, μ»΄ν“¨ν„°λŠ” μ˜€λ²„ν”Œλ‘œμš°(Overflow) 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚€κ²Œ λœλ‹€. 

 

[직관적인 풀이2] = μ‹œκ°„λ³΅μž‘λ„ O(n). 이 λ°©μ‹μœΌλ‘œ ν’€κ²Œλ˜λ©΄ μ‹œκ°„μ΄ˆκ³Όλ‘œ μ˜€λ‹΅ μ²˜λ¦¬λœλ‹€.

#pragma warning(disable:4996) //visual studio scanf 였λ₯˜ 방지.
#include <stdio.h>

int get_units(int a, int b) {
	int units = a % 10;

	for (int i = 1; i < b; i++)
		units = (units * a) % 10;
        
		/*
		units = ( units * (a%10) ) % 10 
		μœ„ μ‹μœΌλ‘œ 계산해도 λœλ‹€.
		*/
        
	return units;
}

int main(int argc, char* argv[]) {
	/* λ³€μˆ˜μ„ μ–Έ */
	int a, b, T;

	/* μž…λ ₯κ°’ 받은 ν›„ μ—°μ‚° */
	scanf("%d", &T);
	for (int i = 0; i < T; i++) {
		scanf("%d %d", &a, &b);
		printf("%d\n", get_units(a, b) == 0 ? 10 : get_units(a, b));
	}

	return 0;
}

μœ„ μ½”λ“œμ—μ„œ get_units(int a, int b) ν•¨μˆ˜λŠ” a와 bλ₯Ό μž…λ ₯κ°’μœΌλ‘œ λ°›μ•„, $a^b$의 끝자리(=일의자리) 수λ₯Ό λ°˜ν™˜ν•΄ μ£ΌλŠ” ν•¨μˆ˜μ΄λ‹€. 

[직관적인 풀이1]μ—μ„œ λ°œμƒν•œ μ˜€λ²„ν”Œλ‘œμš° 방지λ₯Ό μœ„ν•΄, %10 연산을 톡해 κ°’μ˜ 크기λ₯Ό 쀄여주고 μžˆλ‹€. λ‹€λ§Œ, 이 λ°©μ‹μ˜ 경우 λ³€μˆ˜ b에 λŒ€ν•΄ O(n)의 μ„ ν˜•μ μΈ μ‹œκ°„λ³΅μž‘λ„λ₯Ό μ§€λ‹Œλ‹€. 즉, b의 크기가 컀질 경우 μ‹œκ°„λ³΅μž‘λ„λ„ 그에 λΉ„λ‘€ν•˜μ—¬ μ¦κ°€ν•œλ‹€.

 

μ—­μ‹œλ‚˜ μœ„ ν’€μ΄λŒ€λ‘œ 백쀀에 채점을 μš”μ²­ν•œ κ²°κ³Ό, μ‹œκ°„μ΄ˆκ³Όκ°€ λ°œμƒν•œλ‹€. 

O(n)μ—μ„œ μ‹œκ°„λ³΅μž‘λ„λ₯Ό λ”μš± 쀄여야 ν–ˆλŠ”λ°, μ•„λž˜ μ„œμˆ ν•  μˆ˜ν•™μ  원리λ₯Ό μ΄μš©ν•˜λ‹ˆ O(1) μƒμˆ˜μ‹œκ°„ λ‚΄λ‘œ λ¬Έμ œκ°€ ν’€λ Έλ‹€.

 

[μ •λ‹΅] = μ‹œκ°„λ³΅μž‘λ„ O(1)

고민을 ν•΄λ³΄μž. μš°λ¦¬κ°€ ꡬ해야 ν•  값은 $a^b$의 끝자리(=일의자리) 이닀. 

$a^b$λž€ aλž€ 값을 b번 κ³±ν–ˆμ„ λ•Œ μ–»μ–΄μ§€λŠ” μˆ˜μ΄λ‹€, b번의 κ³±μ…ˆμ„ λ°˜λ³΅ν–ˆμ„ λ•Œ, 일의자리 수의 λ³€ν™”μ—λŠ” κ·œμΉ™μ΄ μ‘΄μž¬ν• κΉŒ?

  [b%4=1]
1번, 5번, 9번, .. 
[b%4=2]
2번, 6번, 10번, .. 
[b%4=3]
3번, 7번, 11번, .. 
[b%4=0]
4번, 8번, 12번, .. 
일의자리 = 0 0 0 0 0
일의자리 = 1 1 1 1 1
일의자리 = 2 2 4 8 6
일의자리 = 3 3 9 7 1
일의자리 = 4 4 6 4 6
일의자리 = 5 5 5 5 5
일의자리 = 6 6 6 6 6
일의자리 = 7 7 9 3 1
일의자리 = 8 8 4 2 6
일의자리 = 9 9 1 9 1

μœ„ ν‘œλ₯Ό 톡해 '같은 수λ₯Ό λ¬΄ν•œνžˆ κ³±ν•΄λ‚˜κ°ˆ μ‹œ, μΌμ˜μžλ¦¬λŠ” μ΅œλŒ€ 4주기둜 같은 μˆ˜κ°€ λ°˜λ³΅λœλ‹€' λΌλŠ” 사싀을 깨달을 수 μžˆλ‹€.

λ”°λΌμ„œ, μœ„ ν‘œμ™€ 같은 배열을 미리 λ§Œλ“€μ–΄ λ‘” ν›„, a와 b에 μ μ ˆν•œ 연산을 톡해 값을 μ„œλ‘œ λ§€μΉ­μ‹œν‚€λ©΄ O(1)의 μ‹œκ°„ λ‚΄λ‘œ λ¬Έμ œκ°€ ν’€λ¦¬κ²Œ λœλ‹€.

 

단, μ •λ‹΅ μ½”λ“œμ— λ§Œλ“€μ–΄λ‘” ν…Œμ΄λΈ” = table[10][4] 은 값이 λ‹€μŒκ³Ό 같은 ν˜•νƒœλ‘œ μ €μž₯됨을 유의 λ°”λž€λ‹€.

  [b%4=0]
4번, 8번, 12번, .. 
[b%4=1]
1번, 5번, 9번, .. 
[b%4=2]
2번, 6번, 10번, .. 
[b%4=3]
3번, 7번, 11번, .. 
일의자리 = 0 0 [0][0] 0 [0][1] 0 [0][2] 0 [0][3]
일의자리 = 1 1 [1][0] 1 [1][1] 1 [1][2] 1 [1][3]
일의자리 = 2 6 [2][0] 2 ... 4 8
일의자리 = 3 1 [3][0] 3 9 7
일의자리 = 4 6 [4][0] 4 6 4
일의자리 = 5 5 [5][0] 5 5 5
일의자리 = 6 6 [6][0] 6 6 6
일의자리 = 7 1 [7][0] 7 9 3
일의자리 = 8 6 [8][0] 8 4 2
일의자리 = 9 1 [9][0] 9 1 9

 

[μ£Όμ˜ν•  점]

일의 자리 μˆ˜κ°€ 0이라면, μ΄λŠ” 10번째 컴퓨터가 μ²˜λ¦¬ν•˜λŠ” 값이닀. 0번째 컴퓨터가 μ²˜λ¦¬ν•˜λŠ” 값이 μ•„λ‹ˆλ‹€...이것 λ•Œλ¬Έμ— λͺ‡ 번 ν‹€λ Έλ‹€. μ‘°μ‹¬ν•˜μž.

3. μ½”λ“œ

#pragma warning(disable:4996) //visual studio scanf 였λ₯˜ 방지.
#include <stdio.h>

int table[10][4]; //ν…Œμ΄λΈ” λ§Œλ“€κΈ°

int power(int a, int b) { //κ±°λ“­μ œκ³± ν•¨μˆ˜

	if (b == 0)
		return 1;
	else
		return power(a, b - 1) * a;

}

void make_table(void) { //ν…Œμ΄λΈ” μ±„μ›Œλ„£κΈ°
	
	for (int i = 0; i < 10; i++)
		for (int j = 1; j <= 4; j++)
			table[i][j % 4] = (int)power(i, j) % 10;
		/*
		math.h의 pow()λ₯Ό μ΄μš©ν•˜μ—¬,
		table[i][j % 4] = (int)pow(i, j) % 10; 
		으둜 κ΅¬ν˜„ν•΄λ„ λœλ‹€.
		(math.h ν•¨μˆ˜λŠ” λ°˜ν™˜ν˜•μ΄ doubleμ΄λ―€λ‘œ, int둜 ν˜•λ³€ν™˜ ν•΄μ€€λ‹€.)
		*/

}

int main(int argc, char* argv[]) {

	/* λ³€μˆ˜μ„ μ–Έ */
	int a, b, T;

	/* ν…Œμ΄λΈ” λ§Œλ“€κΈ° */
	make_table();

	/* μž…λ ₯κ°’ 받은 ν›„ μ—°μ‚° */
	scanf("%d", &T);
	for (int i = 0; i < T; i++) {
		scanf("%d %d", &a, &b);
		printf("%d\n", table[a % 10][b % 4] == 0 ? 10 : table[a % 10][b % 4]);
	}

	return 0;
}
728x90
λ°˜μ‘ν˜•