Home 백준 - 2981 검문 풀이
Post
Cancel

백준 - 2981 검문 풀이

문제

2981 검문

screencapture

풀이

1. M 구하기

식 정리

An: 입력 받은 수
an: 몫
M: 제수
r: 나머지

An / M = an … r


An = an * M + r


A0 = a0 * M + r
A1 = a1 * M + r

An-1 = an-1 * M + r
An = an * M + r


r = An-1 - an-1 * M
r = An - an * M


An - an * M = An-1 - an-1 * M
An - An-1 = an * M - an-1 * M


An - An-1 = M * (an - an-1)

결론,
M은 (An - An-1)의 약수이다.
모든 M을 구하기 위해서는 (An - An-1)들의 모든 약수를 구하면 된다.
(An - An-1)들의 모든 약수는 (An - An-1)들의 최대 공약수의 모든 약수이다.

(An - An-1)들의 최대 공약수를 구하자!

코드

1
2
var gcdValue = 0
(1..inputs.lastIndex).forEach { gcdValue = gcd(kotlin.math.abs(inputs[it] - inputs[it - 1]), gcdValue) }

2. 최대 공약수 구하기

유클리드 호제법

유클리드 호제법(-互除法, Euclidean algorithm) 또는 유클리드 알고리즘은 2개의 자연수 또는 정식(整式)의 최대공약수를 구하는 알고리즘의 하나이다. 호제법이란 말은 두 수가 서로(互) 상대방 수를 나누어(除)서 결국 원하는 수를 얻는 알고리즘을 나타낸다. 2개의 자연수(또는 정식) a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면(단, a>b), a와 b의 최대공약수는 b와 r의 최대공약수와 같다. 이 성질에 따라, b를 r로 나눈 나머지 r’를 구하고, 다시 r을 r’로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수가 a와 b의 최대공약수이다.

유클리드 호제법
유클리드 호제법

코드

1
2
3
4
fun gcd(a:Int, b:Int):Int = when(b) {
    0 -> a
    else -> gcd(b, a%b)
}

3. 최대 공약수의 모든 약수 구하기

모든 약수 구하기

n보다 작은 n을 나누면 나머지가 0이 되는 수가 있는 지 확인하면 된다. 1은 제외한다는 조건이 있기때문에 2부터 n까지 모든 수를 검사하면 된다.
하지만, 시간이 이 많이 걸린다.(해보니 시간 초과에 걸리진 않지만, 시간 차이는 많이 난다.)
최적화를 하면, 2부터 n까지가 아닌 ⌊√n⌋까지만 진행하면 된다.
수가 수를 나누기 위해서는 그 몫이 항상 필요하며 나누는 수와 몫 중 어느 하나는 반드시 √n이하이기 때문이다.[소수 (수론)]

코드 1: 2부터 n까지 검사

1
2
val output = StringBuilder()
(2..gcdValue).forEach { if(gcdValue % it == 0) output.append(it).append(' ') }

코드 2: 2부터 ⌊√n⌋까지 검사(최적화)

1
2
3
4
5
6
val outputSet = mutableSetOf(gcdValue)
val sqrtGcdValue = kotlin.math.sqrt(gcdValue.toDouble()).toInt()
(2..sqrtGcdValue).forEach { if(gcdValue % it == 0) {outputSet.add(it); outputSet.add(gcdValue/it); }}

val output = StringBuilder()
outputSet.sorted().forEach{ output.append(it).append(' ') }

kotlin code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fun main() {
    val inputs = IntArray(readln().toInt()) { readln().toInt() }

    var gcdValue = 0
    (1..inputs.lastIndex).forEach { gcdValue = gcd(kotlin.math.abs(inputs[it] - inputs[it - 1]), gcdValue) }
    
    val outputSet = mutableSetOf(gcdValue)
    val sqrtGcdValue = kotlin.math.sqrt(gcdValue.toDouble()).toInt()
    (2..sqrtGcdValue).forEach { if(gcdValue % it == 0) {outputSet.add(it); outputSet.add(gcdValue/it); }}

    val output = StringBuilder()
    outputSet.sorted().forEach{ output.append(it).append(' ') }

    println(output)
}

fun gcd(a:Int, b:Int):Int = when(b) {
    0 -> a
    else -> gcd(b, a%b)
}

Reference

This post is licensed under CC BY 4.0 by the author.

백준 - 1436 영화감독 숌 풀이

github blog(jekyll chirpy 테마)에 utterances 댓글 위젯 추가 하기