백준 15501 '부당한 퍼즐'

DoubleDeltas·2025년 12월 27일

알고리즘 문제풀이

목록 보기
111/111

https://www.acmicpc.net/problem/15501

아이디어

순열을 뒤집는 연산을 FF, 왼쪽으로 미는 연산을 LL, 오른쪽으로 미는 연산을 RR이라 하자.

순서대로 연산들을 적용하는 것을 기호를 오른쪽으로 연이어 표시하자. 예를 들어 FLFL은 순열을 뒤집은 후 왼쪽으로 밀었음을 나타낸다.

이제 FF, LL, RR 사이에서 자명하게 성립하는 법칙들을 확인해보자.

  1. 각 연산에는 반대 연산이 존재한다: F1=F,L1=R,R1=LF^{-1}=F, L^{-1}=R, R^{-1}=L
  2. 순열을 2번 뒤집은 것은 원래의 순열과 같다: FF=idFF = \mathrm{id}
  3. 왼쪽(오른쪽)으로 nn번 미는 것은 원래의 순열과 같다: Ln=Rn=idL^n=R^n=\mathrm{id}
  4. 연산들 후 뒤집는 것은, 뒤집은 후 연산들을 반대로 하는것과 같다: XF=FX1XF=FX^{-1}

위의 법칙들을 통해 서로 다른 연산들의 조합은 다음 2n2n개의 조합 밖에 없음을 알 수 있다.
{id,L,LL,,Ln1,  F,LF,LLF,,Ln1F}\left\{\mathrm{id}, L, LL, \cdots, L^{n-1},\ \ F, LF, LLF, \cdots, L^{n-1}F\right\}
그러므로, 알고리즘은 다음과 같이 생각해볼 수 있다.

순열을 왼쪽으로 밀고, 같은지 확인하는 과정을 nn번 반복한 후, 같지 않았다면 뒤집어서 nn번 더 시행해본다. 그래도 같지 않으면 두 순열을 같게 만들 수 없는 것.

코드 (Python)

from collections import deque

n = int(input())
p = deque(map(int, input().split()))
q = deque(map(int, input().split()))

for _ in range(n):
    q.rotate(-1)
    if p == q:
        print("good puzzle")
        exit(0)
r = deque([*q][::-1])
for _ in range(n):
    r.rotate(-1)
    if p == r:
        print("good puzzle")
        exit(0)
print("good puzzle" if p == q else "bad puzzle")

메모리 및 시간

  • 메모리: 265948 KB
  • 시간: 724 ms

개선 방법

  • 굳이 모든 경우를 확인하지 않더라도, 첫번째 원소를 고정시킨 후 비교해도 된다.
    • LiL^i 연산이 LLii번 하는 것보다 빠를 것이므로...
  • FF, LL, RR로는 인접한 원소의 순서를 바꿀 수 없다는 사실을 이용해도 된다.
    • FF는 왼쪽/오른쪽만, L,RL, R은 원소의 절대적인 인덱스만 바꾼다.
profile
유사 개발자

0개의 댓글