전혀 쉽지 않은 문제였다. 각 값을 소인수분해 한 결과를 vector에 저장하고, 해당 소인수분해 결과를 종합해서 입력된 값들이 가질 수 있는 최대공약수를 구하고, 각각의 값들이 해당 최대공약수를 만족하기 위해 필요한 값의 갯수를 찾아서 합치면 된다.
어찌보면 그냥 수학 문제인데, 생각보다 많이 어려웠다.
#include <iostream> #include <utility> #include <vector> #include <map> #include <cmath> using namespace std; int numbers[101], N, sieve[1001]; vector<pair<int,int>> datas[101]; map<int,int> sum; pair<int,int> dummy; void print_vector(){ for(int i = 0 ; i < N; i++){ vector<pair<int,int>> target = datas[i]; printf("%d : ", i); for(int j = 0; j < (int) target.size(); j++){ printf("(%d %d) ", target[j].first, target[j].second); } printf("\n"); } } int main(){ scanf("%d", &N); for(int i = 0 ; i < N ; i++){ scanf("%d", &numbers[i]); } for(int i = 2; i < 1001; i++) { sieve[i] = 1; }; // 에라토스테네스의 체 for(int i = 2 ; i < 1001; i++){ if(!sieve[i]) continue; for(int j = i * 2; j < 1001; j += i){ sieve[j] = 0; } } // 각 수를 소인수분해한 결과를 datas에 넣기 for(int i = 0 ; i < N ; i++){ int data = numbers[i]; for(int j = 0 ; j < 1001; j++){ if(!sieve[j]) continue; int count_common_divider = 0; while((data % j) == 0){ data /= j; count_common_divider++; } if(count_common_divider){ dummy.first = j; dummy.second = count_common_divider; datas[i].push_back(dummy); } if(data == 1) break; } if(data != 1){ datas[i].push_back(make_pair(data, 1)); } } print_vector(); // 모든 수를 곱한 결과를 Map에 넣기 for(int i = 0 ; i < N ; i++){ vector<pair<int,int>> target = datas[i]; for(auto tup : target){ map<int,int>::iterator it = sum.find(tup.first); if(it != sum.end()){ it->second += tup.second; } else { sum.insert(tup); } } } int total = 1; int count = 0; // 생성할 수 있는 최댓값과, 최댓값을 생성하기 위해 필요한 수의 갯수를 구한다. for(map<int, int>::iterator it = sum.begin() ; it != sum.end(); ++it){ it->second /= N; // printf("(%d %d)\n", it->first, it->second); for(int i = 0 ; i < it->second; i++){ total *= it->first; } count += it->second; } int result = 0; int need_to_change; // 하나의 수에 대해서, 생성할 수 있는 최대공약수와 갯수차이를 구한다. // 각각의 숫자에 대해서 대해서 for(int i = 0 ; i < N ; i++){ vector<pair<int,int>> target = datas[i]; // 갯수 차이는 처음엔 필요한 수의 갯수로 초기화 need_to_change = count; // 해당 숫자의 약수들에 대해서 for(auto got : target){ map<int, int>::iterator it = sum.find(got.first); printf("%d %d %d\n", got.first, it->second, got.second); // 필요한 약수보다 적을 때 현재 가진 양만큼 제거한다. if(it->second > got.second){ need_to_change -= got.second; } // 필요한 약수보다 많으면 이미 모두 충족됬으므로 필요한 양만큼 제거한다. else { need_to_change -= it->second; } } result += need_to_change; } printf("%d %d", total, result); return 0; }
'백준 > 카테고리별' 카테고리의 다른 글
[단계별로 풀어보기] - 유니온 파인드 (6) | 2020.07.07 |
---|---|
[BOJ] 단계별로 풀어보기 - 우선순위 큐 (0) | 2020.07.06 |
[BOJ] 11000 강의실 배정 (0) | 2020.04.17 |
[BOJ] 7579 앱 (0) | 2020.04.16 |
[BOJ] 11562 백양로 브레이크 (0) | 2020.04.14 |
댓글