티스토리 뷰
[Codeforces 1034A] Enlarge GCD - 1700
문제 설명 :
n개의 숫자가 주어진다. 이 중에서 숫자 k 개를 삭제한 뒤 나머지 (n-k)개 수들의 GCD(최대공약수)가 삭제하기 이전의 GCD보다 크도록 만들어야 한다. 그러기 위해서는 최소 몇 개의 숫자를 삭제해야 하는지 구하는 문제이다(= 가장 작은 k값을 구하여라).
풀이 :
먼저 N개 수들의 GCD를 먼저 구한 뒤, 다시 모든 수들을 GCD로 나눠준다. 나눠진 수들의 GCD는 당연히 1이다. 이 숫자들을 각각 소인수분해하여 가장 많이 등장하는 소인수의 횟수를 N에서 빼주면 된다. 가장 많이 등장하는 소인수를 포함하지 않은 수들을 모두 삭제하고 나면, 그 소인수를 GCD로 취할 수 있기 때문이다.
그리고 이 문제에서 중요한 issue가 되는 것이 소인수분해이다. for문안에 while문을 넣는 소인수분해 방법은 크기가 RANGE인 수 하나를 소인수분해 하는데 시간이 O(sqrt(RANGE))만큼 소모된다. 따라서 이 문제에서 수의 범위가 최대 1500만이고 개수는 30만개이므로 O( sqrt(1500만) * 30만 )을 하면 10억이 훌쩍 넘어간다. 따라서 소인수분해를 다른 방법으로 해야한다. 이에 대한 방법은 마침 얼마 전에 reference로 작성했었던 소인수분해에 나와있다. 복습을 다시 해보자면 에라토스테네스의 체를 변형하여 1~RANGE까지의 모든 수에 대하여 해당 숫자가 가지는 가장 작은 인수를 저장하는 전처리 과정을 거친다. 이 알고리즘의 시간복잡도는 O( RANGE * log(log(RANGE) )이다. RANGE=1500만을 대입해보면 정말 아슬아슬하게 5000만 정도이다. 아무튼 첫 번째 소인수분해 방법보다는 빠르니 이 방법을 사용해야 한다는 것은 확실하다.
주의할 점 :
위 풀이로 제출하면 1초 제한에 무려 997ms가 나온다. 소인수분해 과정에서 걸리는 cost가 거의 대부분이다. 다른 사람들의 코드를 보니 더 최적화를 거쳐서 600ms까지 줄이기는 하는데 나는 거기까지의 최적화는 잘 모르겠다. 다만 이 풀이가 정해인 것은 확실한데 시간이 너무 촉박한 걸 보니 문제에 논란의 여지가 있기는 하다.
배운 점 :
오랜만에 GCD구하는 코드를 remind했다.
소인수분해를 해야할 숫자가 많아지면 에라토스테네스의 체를 이용한 방법을 사용하자.
코드 :
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 | #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; 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= 3000009; const int RANGE=15000009; int arr[SIZE]; int minfact[RANGE]; map<int,int> after; int getGCD(int a,int b){ return (b==0)? a : getGCD(b,a%b); } int main(){ int n; scanf("%d",&n); int G; for(int i=1 ; i<=n ; i++){ scanf("%d",&arr[i]); if(i==1) G=arr[i]; else G=getGCD(G,arr[i]); } for(int i=2 ; i<RANGE ; i++) minfact[i]=i; for(int i=2 ; i*i<RANGE ; i++){ for(int j=i*i ; j<RANGE ; j+=i){ if(minfact[j]==j){ minfact[j]=i; } } } for(int i=1 ; i<=n ; i++){ arr[i]/=G; set<int> tmp; while(arr[i]>1){ tmp.insert(minfact[arr[i]]); arr[i]/=minfact[arr[i]]; } for(int here:tmp) after[here]++; } int max_cnt=0; for(auto here:after){ max_cnt=max(max_cnt,here.second); } if(max_cnt==0) printf("-1\n"); else printf("%d\n",n-max_cnt); return 0; } | cs |
'Problem Solving > Implementation' 카테고리의 다른 글
[Codeforces 1163B2] Cat Party (Hard Edition) (0) | 2019.05.11 |
---|---|
[Codeforces 1108E1] Array and Segments (Easy version) (0) | 2019.05.06 |
[Codeforces 1080C] Masha and two friends (0) | 2019.04.17 |
[Codeforces 1082C]Multi-Subject Competition (0) | 2019.03.26 |
[Codeforces 1082B] Vova and Trophies (0) | 2019.03.25 |