Algorithm/math

[백준] 알고리즘 C++ 2981번 - 검문문제

낭강 2022. 1. 19. 17:21
문제

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

 

2981번: 검문

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

www.acmicpc.net

소스코드
/******************************************************************************

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby, 
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.

*******************************************************************************/
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int arr[101];
vector<int> ans;
int gcd(int a,int b){
    if(a%b==0){
        return b;
    }
    return gcd(b,a%b);
}
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++) cin>>arr[i];
    sort(arr,arr+n);
    int g=arr[1]-arr[0];
    for(int i=2;i<n;i++){
         g=gcd(g,arr[i]-arr[i-1]);
    }
    for(int i=2;i*i<=g;i++){
        if(g%i==0){
            ans.push_back(i);
            ans.push_back(g/i);
        }
    }
    ans.push_back(g);
    sort(ans.begin(),ans.end());
    ans.erase(unique(ans.begin(),ans.end()),ans.end());
    for(int i=0;i<ans.size();i++){
        cout<<ans[i]<<" ";
    }
}
해설

1. 나머지가 같게 된다.

2. M이 하나 이상 무조건 존재한다.

이 두가지의 키워드를 가지고 문제를 접근해볼 수 있다.

 

처음 모든 경우의 수의 최대공약수를 구한 후 그 gcd에서 약수를 구해주면 정답이지만, 시간초과가 날게 뻔하다.

 

우리는 수학적으로 접근해보아야 한다.

a = m*a+r

b=m*b+r

c=m*c+r

여기에서 우리는 나머지가 같다는 것을 알 수 있다. 나머지도 같고 m도 주어진 수들에 대해서 나누었을 때 나머지가 같도록 같은 수라고 생각할 수 있다. 그렇다면 빼보면 어떻게 될까

a-b=m(a-b) + (r-r)

결국 m을 찾기 위해서는 a-b의 최대공약수를 구한 후 약수들이 m이라고 볼 수 있다.

결국 a-b b-c 이런식으로 n 까지 최대공약수를 구해서 약수들을 구해주면 된다.

 

약수들을 구하고 난 이후에 자기자신을 포함해서 정렬을 한 이후, 중복된 원소를 제거해준다.