본문 바로가기
Probelm Solving/BOJ

BOJ2478 자물쇠

by garrrruii 2021. 1. 7.

www.acmicpc.net/problem/2478

 

2478번: 자물쇠

처음 k-왼쪽밀기의 k를 첫째 줄에, (p,q)-구간뒤집기의 p와 q를 빈칸을 사이에 두고 둘째 줄에, 그리고 마지막 k-왼쪽밀기의 k를 셋째 줄에 출력한다. 만일 답이 여럿일 경우에는 그 중 하나만 출력

www.acmicpc.net

 

 

 

입력에 맞는 답 (k1, p, q, k2)가 여러 개 존재한다. 아래처럼 둘 중 뭐가 돼도 상관없다는 걸 먼저 파악함. 그 다음엔 가장 구하기 편한 걸 구하기로 했다.

(3, 5, 7, 3): 12345678 45678123 45672183 → 72183456

(5, 3, 5, 1): 12345678 → 67812345 → 67218345 → 72183456

 

아래 여섯 가지 예시로 생각해보았다. 밑줄이 뒤집어진 부분

ex input Step 1 Step 2 Step 3 (k1, p, q, k2)
7 2 1 8 3 4 5 6 p=2 q=4 x=3 k2=8 k1=6 (6, 2, 4, 8)
4 7 6 5 8 1 2 3 p=2 q=4 x=6 k2=8 k1=3 (3, 2, 4, 8)
7 3 4 5 6 2 1 8 p=6 q=1 x=7 k2=3 p=1 q=4 x=2 k1=6 (6, 1, 4, 3)
6 5 4 8 1 2 3 7 p=8 q=3 x=5 k2=1 p=1 q=4 x=2 k1=3 (3, 1, 4, 1)
8 7 6 5 4 3 2 1 p=1 q=8 x=1 k2=8 k1=8 (8, 1, 8, 8)
3 2 1 4 5 6 7 8  p=1 q=3 x=1 k2=8 k1=8 (8, 1, 3, 8)

 

Step 1. 처음 입력받은 배열 상 x, p, q를 찾는다. (x = 1의 위치)

for문 돌려서 a[i+1]-a[i] != 1, -1, 1-N, N-1 => p=i+1, q=i, (p, q 순차적으로) 구한다

 

예외처리한다.

1)  8 7 6 5 4 3 2 1

for문이 끝나도 p=q=0이 됨. 수열 전체를 뒤집은 경우이기 때문에 p=1, q=N으로 설정

 

2)  3 2 1 4 5 6 7 8

for문이 끝나면 p=4, q=0이 되어있음. p=1, q=p-1로 바꿈. 여기선 p=1, q=3이 되겠다.

 

3)  7 3 4 5 6 2 1 8 ③. ④도 마찬가지다.

for문에 따르면 '7 3'에 의해 p=2, '6 2'에 의해 q=5라고 구해짐. 순방향인 구간을 고른 것이다.

p=q+1, q=p-1로 바꿔준다. (p=i+1, q=i로 구하는 거니까) 따라서 표와 같이 p=6, q=1을 얻을 수 있음.

 

 

Step 2. k2 구한다.

if)  p<q ①②⑤⑥

k2=N으로 둔다. k1만큼 왼쪽으로 이동, p, q 바꾸고, 한 바퀴 돌린 결과라고 하면 되니까

 

else)  ③④

역방향인 구간이 앞부분과 뒷부분에 걸친 경우이다.

k2=N-p+1로 두고 p, q, x에 각각 k2만큼 더해서 결과적으로 p=1이 되도록 옮긴다.

이때 x>N이면 N을 한 번 더 빼주는 거 잊지 말고

③의 경우 k2=8-6+1=3에 의해 2 1 8 7 3 4 5 6 → 7 3 4 5 6 2 1 8 가 됐다.

 

 

Step 3. k1 구한다.

처음 위치가 1이었던 수는 왼쪽으로 N-x+1만큼 움직여야 x에 위치한다. (1-move+N=x ⇒ move=N-x+1)

 

if)  p≤x≤q ①③⑤⑥

뒤집으면 x의 위치가 p+(q-x)로 바뀐다. k1=N-(p+(q-x))+1=N-p-q+x+1

 

else)  ②④:  k1=N-x+1

 

 

코드

더보기
#include <cstdio>
using namespace std;

int main() {
	int a[501], N, k1, k2, p, q, x, tmp;
	scanf("%d", &N);
	for (int i = 1; i <= N; ++i) scanf("%d", &a[i]);

	k1 = k2 = p = q = x = 0;//= y = 0;
	for (int i = 1; i < N; ++i) {
		if (a[i] == 1) x = i;

		tmp = a[i + 1] - a[i];
		if (tmp == 1 || tmp == -1 || tmp == N - 1 || tmp == 1 - N) continue;

		if (!p) p = i + 1;
		else if (!q) q = i;
	}
	if (!p && !q) p = 1, q = N;		//(87654321)
	else if (!q) q = p - 1, p = 1;		//4321)(8765
	if (!x) x = N;

	if (a[p] == a[p + 1] - 1 || (a[p] == N && a[p + 1] == 1)) {
		tmp = p, p = q + 1, q = tmp - 1;
		k2 = N - p + 1, p = 1, q += k2, x += k2;
		if (x > N) x -= N;
	}
	else k2 = N;
	//if:   654)8123(7 7)3456(218
	//else: 7(218)3456 4(765)8123

	if (p <= x && x <= q) k1 = N - p - q + x + 1;
	else k1 = N - x + 1;
	//if:   7(218)3456 7)3456(218
	//else: 654)8123(7 4(765)8123

	printf("%d\n%d %d\n%d\n", k1, p, q, k2);
	return 0;
}

 

 

더보기

여러 번 틀린 문제. 역시나 처음에 ①~④만 생각하고 대충 냈다가 틀렸습니다 받음,, 한 번 더 고쳐서야 맞았다.

유연한 사고가 되지 않아서 저번에 풀 때나 이번에 풀 때나 가능한 경우를 다 생각해보는 방식으로 풀었는데

 

좀 조잡한 것 같기도 하고

 

'Probelm Solving > BOJ' 카테고리의 다른 글

BOJ13976 타일 채우기 2  (0) 2021.01.28
BOJ11062 카드 게임  (0) 2021.01.28
BOJ1019 책 페이지  (0) 2021.01.12
BOJ13977 이항 계수와 쿼리  (2) 2021.01.12
BOJ11003 최솟값 찾기  (4) 2021.01.12

댓글