[BOJ] Moo 게임 5904 C++ 풀이 [분할정복]
Updated:
문제
Moo는 술자리에서 즐겁게 할 수 있는 게임이다. 이 게임은 Moo수열을 각 사람이 하나씩 순서대로 외치면 되는 게임이다.
Moo 수열은 길이가 무한대이며, 다음과 같이 생겼다.
m o o m o o o m o o m o o o o m o o m o o o m o o m o o o o o
Moo 수열은 다음과 같은 방법으로 재귀적으로 만들 수 있다. 먼저, S(0)을 길이가 3인 수열 “m o o”이라고 하자. 1보다 크거나 같은 모든 k에 대해서, S(k)는 S(k-1)과 o가 k+2개인 수열 “m o … o” 와 S(k-1)을 합쳐서 만들 수 있다.
S(0) = "m o o"
S(1) = "m o o m o o o m o o"
S(2) = "m o o m o o o m o o m o o o o m o o m o o o m o o"
위와 같은 식으로 만들면, 길이가 무한대인 문자열을 만들 수 있으며, 그 수열을 Moo 수열이라고 한다.
N이 주어졌을 때, Moo 수열의 N번째 글자를 구하는 프로그램을 작성하시오.
입력
첫째 줄에 N (1 ≤ N ≤ 10^9)이 주어진다.
출력
N번째 글자를 출력한다.
접근방법
일정한 패턴으로 반복되는 Moo 문자열을 보며 하나의 긴 Moo 문자열을 작은 단위로 쪼개어 나아갔을때 N번째 글자에 해당하는 문자를 찾을 수 있을 것이라 생각하였다.
예제의 S$($2) m o o m o o o m o o
m o o o o
m o o m o o o m o o
에서 n=5인 경우를 보면
S$($2) 문자열은 총 세개의 구간으로 나눌 수 있다. S$($1) + $($m o o o + o
) + S$($1)
이때 5번째 문자는 세개의 구간 중 앞의 S$($1)에 속하여 있으므로 앞부분만을 때어내어 이번에는 S$($1)을 다시 세 등분해서 진행한다.
` m o o
m o o o ` m o o
여기서 5번째 문자는 중간 구간에 속해있으므로 이 경우에는 n - 앞의 S(0)문자열의 길이
의 값이 1인 경우 m을 출력하고 아닌경우 o를 출력하며 반복문을 탈출하면 된다.
찾고자 하는 문자가 세 구간의 제일 뒷부분에 존재하는 경우에는 앞의 두 구간의 경우와 달리 n의 값도 같이 갱신해 줘야 한다. n -= prev + mid;
구현
#include<iostream>
using namespace std;
int main(void)
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
int mid;
int total_len, prev;
total_len = prev = mid = 3;
cin>>n;
while(n > total_len)
{
int tmp = (total_len * 2) + ++mid;
total_len = tmp;
}
while(true)
{
prev = (total_len - mid) / 2;
if(n <= prev)
{
total_len = prev;
mid--;
continue;
}
if(n > prev+mid)
{
total_len = prev;
n -= prev + mid;
mid--;
continue;
}
n -= prev;
break;
}
if(n == 1) cout<<'m';
else cout<<'o';
return 0;
}
오답노트
세 구간 중에서 찾고자 하는 문자가 뒷 구간에 있는 경우 n값을 갱신해 줘야 한다는 것을 인지하지 못하여 시간초과가 발생하였다.
Leave a comment