https://www.acmicpc.net/problem/16936
16936번: 나3곱2
나3곱2 게임은 정수 하나를 이용한다. 가장 먼저, 정수 x로 시작하고, 연산을 N-1번 적용한다. 적용할 수 있는 연산은 두 가지 있고, 아래와 같다. 나3: x를 3으로 나눈다. x는 3으로 나누어 떨어져야
www.acmicpc.net
문제 해설
1. 나3 : x를 3으로 나눈다. x는 3으로 나누어 떨어져야 한다.
2. 곱2 : x를 2로 곱한다.
어떤 수 x에 1, 2 두 가지 연산을 N번 시행했을 때, 수열 A가 나온다.
이 수열 A의 순서를 뒤섞은 수열 B로부터 A를 찾아내는 문제다.
살펴볼 것
1. 주어진 수열에 있는 원소는 중복이 있을까?
중복은 없다.
연산은 3으로 나누거나 2로 곱하는 것뿐이다.
게임의 시작을 정수 x = q * 2^a * 3^b (q는 2, 3과 각각 서로소)로 둔다면,
다음 수는 y = q * 2^(a+1) * 3 ^(b) 이거나 y = q * 2^(a) * 3 ^(b-1)가 되고(a가 증가하거나 b가 감소한다),
이후 모든 수들은 z = q * 2^(a`) * 3^(b`) (단, (a <= a` and b >= b`) and !(a == a' and b == b`)가 될 것이다.
즉, 수열에 있는 임의의 수 x = q * 2^a * 3^b (q는 2, 3과 각각 서로소)를 고른다면,
x가 아닌 임의의 수 y = q * 2^(a`) * 3^(b`) (단, a != a` 이거나 b != b`)로 표현될 수 있다.
2. 가능한 정답은 여러 개일까?
유일하다.
항상 정답이 존재하는 경우에만 입력으로 주어지므로 수열 내의 특정한 수 x를 고를 경우,
수열은 { (x/2 존재) xor (3x 존재) } or { (2x 존재) xor(x/3 존재) }를 만족해야 한다. (만족하지 않는 경우 수열엔 x뿐)
위의 중괄호 속에 있는 식을 만족하는 수가 존재한다면 수의 위치는 유일하다.(바로 앞 또는 바로 뒤)
왜냐하면, 2와 3은 서로소이고, 연산은 3으로 나누거나 2로 곱하는 것뿐이기 때문이다.
ex)
나4곱2문제였다면 원소들 사이 순환이 생기기 때문에 정답은 유일하지 않다.
나3곱3문제인경우도 같은 이유로 정답이 유일하지 않다.
해답
정답이 유일하므로, 주어진 원소 중 아무 수 x를 고른다면,
수열이 { (x/2 존재) xor (3x 존재) } or { (2x 존재) xor(x/3 존재) }를 만족하거나, 더 이상의 원소가 없다.
앞의 중괄호 { (x/2 존재) xor (3x 존재) }를 만족하는 수가 존재한다면, 정렬되었을 때 해당 수는 x 앞에,
뒤의 중괄호 { (2x 존재) xor(x/3 존재) }를 만족하는 수가 존재한다면, 정렬되었을 때 해당 수는 x 뒤에 위치하게 될 것이다.
이제 우리는 해당 수가 있는지 없는지만 판단하면 되므로, 유일한 값들을 저장하는 set으로부터 만족하는 수를 찾으면 된다. 그리고, 찾은 수는 x앞 혹은 뒤에 존재해야 하므로 deque를 이용해 양방향 모두 입력받도록 한다.
#include <iostream>
#define fio cin.tie(0)->sync_with_stdio(0)
using namespace std;
#include <set>
#include <deque>
using ll = long long;
int main() {
fio;
set<ll> set_;
int N; cin>>N;
ll start; cin >> start;
set_.insert(start);
for(int i=0; i <N-1;i++){
ll tmp; cin >> tmp;
set_.insert(tmp);
}
//
deque<ll> dq;
dq.push_back(start);
//
ll now;
now = start;
while(1){//to the left
ll prev = now;
if(now % 2 == 0 && set_.find(now/2) != set_.end()){
prev = now/2;
}
if(set_.find(now*3) != set_.end()){
prev = now*3;
}
if(prev == now){//둘 다 없는 경우
if(set_.find(now) != set_.end())
set_.erase(now);
break;
}else{
dq.push_front(prev);
if(set_.find(now) != set_.end())
set_.erase(now);
now = prev;
}
}
//
now = start;
while(1){//to the right
ll next = now;
if(now % 3 == 0 && set_.find(now/3) != set_.end()){
next = now/3;
}
if(set_.find(now*2) != set_.end()){
next = now*2;
}
if(next == now){//둘 다 없는 경우
if(set_.find(now) != set_.end())
set_.erase(now);
break;
}else{
dq.push_back(next);
if(set_.find(now) != set_.end())
set_.erase(now);
now = next;
}
}
//
while(!dq.empty()){
cout << dq.front()<<' ';
dq.pop_front();
}
return 0;
}
'알고리즘 > 백준' 카테고리의 다른 글
백준 BOJ 2749 피보나치 수 3 (0) | 2021.12.30 |
---|---|
백준 BOJ 5582 공통 부분 문자열 (0) | 2021.12.29 |
백준 12015 가장 긴 증가하는 부분 수열 2 +a (0) | 2021.12.28 |
백준 12034 김인천씨의 식료품가게 (Large) (0) | 2021.12.27 |
백준 11645 I’ve Been Everywhere, Man (0) | 2021.12.27 |