티스토리 뷰

[Codeforces 1025B] Weakened Common Divisor - 1600


문제 설명 : 

문제에서 WCD라는 연산을 정의한다. 이 연산은 양의 정수 2개로 구성된 pair가 총 n개 주어질 때 두 수 중에서 최소 1개는 나누어 떨어지는 공약수를 전체 n개의 pair에 대해서 찾을 수 있으면 그 공약수를 구하거나 불가능함을 밝히는 문제이다.


풀이 : 

pair가 최대15만개 주어지므로 숫자는 총 30만개이고 각 수의 최대 범위는 20억이다. naive하게 생각하면 30만개 수를 모두 소인수분해해서 그 수들의 공약수를 찾으면 되는데, 소인수분해 알고리즘의 시간복잡도는 단발성 소인수분해는 O(sqrt(RANGE)), 전처리 소인수분해는 O(N*RANGE*log(log(RANGE)))이다(RANGE는 수의 최대 범위). 이 문제에서는 RANGE=20억이므로 두 알고리즘 모두 사용할 수 없다. 따라서 다른 효율적인 방법이 필요하다. 

그 힌트는 문제에서 찾을 수 있다. 이 문제는 기존의 소인수분해 문제가 아닌, n개의 pair가 주어지고 각 pair의 두 수 중에서 최소 1개로만 나누어 떨어지기만 하면 된다. 즉 전체 n개 pair들의 1이 아닌 공약수가 존재한다면, n개 중 어떤 임의의 pair가 있을 때 그 pair들의 소인수들 중 최소 한개는 다른 (n-1)개의 pair로 나누어 떨어지는게 확실하다. 이런 관점에서 생각하면 조사해야할 범위를 대폭 줄일 수 있다. 어떤 수의 소인수의 최대 개수는 log(RANGE)이고 이를 n개의 수에 대해서 나누어 떨어질 수 있는지 확인하면 되므로 총 시간복잡도는 O(N*log(RANGE))가 된다.


주의할 점 : 

n=1일 때는 소인수분해 할 필요 없이, 두 수 중에서 아무 수나 출력하면 된다.


배울 점 : 

문제의 특성을 생각해서 조사해야할 범위를 크게 줄일 수 있다. 소인수분해 알고리즘은 O(sqrt(RANGE))이지만 소인수의 최대 개수는 log(RANGE)라서 왠만한 범위에서는 소인수의 개수가 더 적기 때문에 조사 범위가 줄었다고 할 수 있다.


코드 :


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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<functional>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<assert.h>
#include<stdlib.h>
#include<stack>
using namespace std;
/*********************Contest Template***********************/
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<long long,long long> pll;
typedef pair<int,int> Cord;
#define FASTIO ios_base::sync_with_stdio(false);cin.tie(0);
struct S{
    int a,b;
 
    S(){}
    S(int _a,int _b){
        a=_a;
        b=_b;
    }
 
    const bool operator<(const S &o) const{
        return a<o.a;
    }
};
priority_queue<int,vector<int>,greater<int>> mpq;
#define SPACE 0
#define NL 1
inline void showAll(vector<int> &v,int NL_or_space){ 
    //0 is space, 1 is NL
    for(int &here:v){
        printf("%d",here);
        printf("%c",(NL_or_space)?'\n':' ');
    }
}
/*********************Contest Template***********************/
const int SIZE= 150009;
 
pii arr[SIZE];
 
int main(){
    int n;  scanf("%d",&n);
 
    for(int i=1 ; i<=n ; i++){
        int a,b;    scanf("%d %d",&a,&b);
        arr[i]={a,b};
    }
 
    if(n==1){
        printf("%d",arr[1].first);
        return 0;
    }
 
    set<int> p_fact;
    int k=arr[1].first;
    for(int i=2 ; i*i<=k ; i++){
        while(k%i==0){
            p_fact.insert(i);
            k/=i;
        }
    }
    if(k!=1) p_fact.insert(k);
 
    k=arr[1].second;
    for(int i=2 ; i*i<=k ; i++){
        while(k%i==0){
            p_fact.insert(i);
            k/=i;
        }
    }
    if(k!=1) p_fact.insert(k);
    
    for(int here:p_fact){
        for(int i=2 ; i<=n ; i++){
            if(arr[i].first%here && arr[i].second%here) break;
            if(i==n) {
                printf("%d",here);
                return 0;
            }
        }
    }
    printf("-1\n");
    return 0;
}
 
 
cs


'Problem Solving > Number Theory' 카테고리의 다른 글

[Codeforces 1151B] Dima and a Bad XOR  (0) 2019.05.26
[Codeforces 1011E] Border  (0) 2019.05.11
댓글