문제 링크
https://www.acmicpc.net/problem/2981
모든 알고리즘 문제는 C++로 구현되어 있습니다.
이 문제는 주어진 수들 간의 차를 전부 구한 뒤, 그 값들의 최대 공약수의 약수를 구해주면 풀 수 있다. 이런 방식으로 답을 구할 수 있는 이유를 알아보자.
주어진 수들을 크기 순으로 나열했을 때, 각각의 수들을 x0, x1, x2, ... ,xn이라 하자. 각각의 수들은 임의의 수 m으로 나눴을 때 모두 동일한 나머지 k를 가지므로 다음과 같이 표현할 수 있다.
x0=a0*m+k
x1=a1*m+k
x2=a2*m+k
.
.
.
xn=an*m+k
(a0, a1, ... , an : x0부터 xn을 m으로 나눴을 때의 몫)
xn과 x0의 차는 (an-a0) * m으로 나타낼 수 있다. 이때 m은 xn-x0의 약수가 된다. 다른 값들 사이의 차도 비슷하게 나타낼 수 있으며, 이 값들의 공약수 집합을 찾아내면 그 값이 m이 된다. 따라서 주어진 수들 간의 차를 전부 구하고, 그 값들의 최대 공약수의 약수를 구해주면 가능한 m을 전부 찾을 수 있다.
전체 코드는 다음과 같다.
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
//2981 검문
int getGcd(vector<int> sub) { //최대공약수를 구하는 함수
int i, j, ret=1;
for (i = 2; i <= sub[0]; ) {
int chk = 0;
for (j = 0; j < sub.size(); j++) {
if (sub[j] % i != 0) {
chk = 1;
i++;
break;
}
}
if (!chk) {
for (j = 0; j < sub.size(); j++) sub[j] /= i;
ret *= i;
}
}
return ret;
}
int main() {
int i, j, n, gcd;
int arr[100];
vector<int> sub, yak;
scanf("%d", &n);
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
sort(arr, arr + n);
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
sub.push_back(arr[j] - arr[i]);
}
}
sort(sub.begin(), sub.end());
gcd=getGcd(sub);
for (i = 2; i*i <= gcd; i++) {
if (gcd % i == 0) {
yak.push_back(i);
yak.push_back(gcd / i);
}
}
yak.push_back(gcd);
yak.erase(unique(yak.begin(), yak.end()), yak.end()); //중복값 제거
sort(yak.begin(), yak.end());
for (auto it = yak.begin(); it != yak.end(); it++) {
printf("%d ", *it);
}
}
'알고리즘 > 백준 알고리즘' 카테고리의 다른 글
[BOJ] 2759 팬케익 뒤집기 (0) | 2020.12.20 |
---|---|
[BOJ] 1637 날카로운 눈 (0) | 2020.12.20 |
[BOJ] 3944 나머지 계산 (0) | 2019.11.25 |
[BOJ] 2003 수들의 합 2 (0) | 2019.11.23 |
[BOJ] 2164 카드 2 (0) | 2019.11.22 |