1. 문제
2. 입출력 및 예제
3. 문제 해설
하나를 뺐을 때 최대공약수가 최대가 되어야한다.
이 문제를 해결하기 위해서는 누적합의 개념을 적용해야한다. 사실 누적합은 누적해서 합을 구하는 것에만 쓰이는 개념은 아니다. 여태까지 나온 값들의 대표값을 의미하기도 한다. 그래서 세그먼트 트리나 인덱스드 트리로도 풀 수 있을 거 같은 문제였다.
핵심 아이디어는 다음과 같다.
LtoR : 왼쪽서부터 최대 공약수를 구해 저장하는 배열
RtoL : 오른쪽서부터 최대 공약수를 구해 저장하는 배열
두 배열이 존재한다면 예제의 경우 다음과 같다.
index | 0 | 1 | 2 | 3 | 4 |
nums | 8 | 12 | 24 | 36 | 48 |
LtoR | 8 | 4 | 4 | 4 | 4 |
RtoL | 12 | 12 | 12 | 12 | 48 |
세 가지의 경우로 나눌 수 있겠다.
먼저 맨 처음 수가 빠지는 경우 12 24 36 48의 최대 공약수를 구해야하므로 RtoL[1]이 되겠다.
두번째로 맨 마지막 수가 빠지는 경우 8 12 24 36의 최대 공약수를 구해야하므로 LtoR[N-2]가 답이 되겠다.
세번째로 가운데의 수가 빠지는 경우이다.
이 때는 나보다 이전까지의 공약수와 나 이후의 공약수의 최대공약수를 구해줘야한다.
24가 빠진다고 생각해보면 8 12까지의 최대공약수와 36과 48의 최대공약수를 구해줘야하므로
LtoR[1]과 RtoL[3]의 최대공약수를 구해주면 되는 것이다. 이런 방식으로 최대가 될 때의 최대공약수와 그 수를 저장해준다.
또한 마지막에 최대가 될 때의 최대공약수가 뺀 수의 약수가 되는 지 모듈러 연산을 통해 확인해준 후 출력해주면 된다.
최대공약수를 구하는 방법은 유클리드 호제법을 사용한다.
#pragma warning (disable : 4996)
#include <cstdio>
using namespace std;
int N; // 수의 개수
int nums[1000002];
int LtoR[1000002];
int RtoL[1000002];
int gcd(int a, int b) {
while (b) {
int c = a % b;
a = b;
b = c;
}
return a;
}
void makeGcds() {
LtoR[0] = nums[0];
RtoL[N - 1] = nums[N - 1];
for (int i = 1; i < N; i++) {
LtoR[i] = gcd(nums[i], LtoR[i - 1]);
RtoL[N - 1 - i] = gcd(nums[N - 1 - i], RtoL[N - i]);
}
}
void sol() {
int ans = RtoL[1]; // 첫번째를 뺏을 때의 경우
int ansNum = nums[0];
for (int i = 1; i < N - 1; i++) {
int temp = gcd(LtoR[i - 1], RtoL[i + 1]);
if (temp > ans) {
ans = temp;
ansNum = nums[i];
}
}
if (LtoR[N - 1] > ans) {
ans = LtoR[N - 1];
ansNum = nums[N - 1];
} // 마지막 수 뺐을 때의 경우
if ((ansNum % ans) == 0) {
// 배수라는 뜻이므로
puts("-1");
}
else {
printf("%d %d",ans, ansNum);
}
}
int main() {
scanf("%d", &N);
for (int i = 0; i < N; i++) {
scanf("%d", &nums[i]);
}
makeGcds();
sol();
return 0;
}
'c++ > 알고리즘' 카테고리의 다른 글
[c++] 카카오 개인정보 수집 유효기간 (문자열 다루기) (0) | 2023.04.27 |
---|---|
[c++] 백준 - 도로 네트워크(lca) (0) | 2023.03.03 |
[c++] 백준 - 케이크 자르기2 10714 (0) | 2023.02.27 |
[c++] 백준 - 1655 가운데를 말해요(우선순위 큐) (1) | 2023.02.16 |
[c++] 백준 - 2014 소수의 곱 (우선순위 큐) (0) | 2023.02.16 |
댓글