본문 바로가기

문제풀이/백준

백준 2981번 검문

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

 

2981번: 검문

트럭을 타고 이동하던 상근이는 경찰의 검문을 받게 되었다. 경찰은 상근이가 운반하던 화물을 하나하나 모두 확인할 것이기 때문에, 검문하는데 엄청나게 오랜 시간이 걸린다. 상근이는 시간��

www.acmicpc.net

풀이

N개의 수 중 i번째 수를 $a_i$라고, 구하고자 하는 값을 $M$이라고 하겠습니다.

N개의 수는 $M$으로 나눈 나머지가 모두 같아야 하므로 이때의 나머지를 $k$라고 하면

$1\leq i\leq N$인 모든 $i$에 대해 $a_i - k$는 $M$의 배수입니다. 

따라서 N개의 수 중 어떤 두 수를 잡더라도 두 수의 차는 $M$의 배수가 됩니다.

즉, $1\leq i, j\leq N$인 모든 $i, j$에 대해 $|a_i - a_j|$는 $M$의 배수입니다. 

이때 가능한 $M$은 모든 인접한 두 수들의 차의 공약수이며,

$M$의 최댓값은 모든 인접한 두 수들의 차의 최대공약수가 됩니다.

식으로 나타내면 $M$의 최댓값 = $\gcd(|a_1 - a_2|, |a_2 - a_3|, ... , |a_{n-1}, a_n|)$이 됩니다.

이렇게 구한 $M$의 최댓값의 약수를 구하면 가능한 $M$의 값을 모두 구할 수 있습니다.

 

코드

유클리드 호제법을 이용하여 인접한 두 수들의 최대공약수를 구했습니다.

M의 최댓값의 약수를 효과적으로 구하기 위해 $\sqrt{M}$번만 루프를 돌았고, 크기순으로 출력하기 위해 루프 안에서 발견되는 약수 중 $\sqrt{M}$ 이상인 수들은 스택에 넣었습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <stack>
using namespace std;
int gcd(int a, int b) {
    if (a % b)
        return gcd(b, a % b);
    else
        return b;
}
stack<int> stk;
int main() {
    int n, got, last = 0, nowgcd = 0;
    scanf("%d"&n);
    while (n--) {
        scanf("%d"&got);
        if (nowgcd)
            nowgcd = gcd(abs(last - got), nowgcd);
        else if (last)
            nowgcd = abs(last - got);
        last = got;
    }
    stk.push(nowgcd);
    for (int i = 2; i * i <= nowgcd; i++) {
        if (!(nowgcd % i)) {
            printf("%d ", i);
            if (i * i != nowgcd)
                stk.push(nowgcd / i);
        }
    }
    while (!stk.empty()) {
        got = stk.top();
        stk.pop();
        printf("%d ", got);
    }
    return 0;
}
cs

 

사족

글 쓸 때 처음으로 LaTeX 사용해봤어요

재밌다!!!

'문제풀이 > 백준' 카테고리의 다른 글

백준 17298번 오큰수  (0) 2020.10.18
백준 2436번 공약수  (0) 2020.10.17
백준 10888번 두 섬간의 이동  (0) 2020.08.27
백준 2660번 회장 뽑기  (0) 2020.08.17
백준 1655번 가운데를 말해요  (0) 2020.08.17