N개의 기차가 어둠을 헤치고 은하수를 건너려고 한다.
기차는 20개의 일렬로 된 좌석이 있고, 한 개의 좌석에는 한 명의 사람이 탈 수 있다.
기차의 번호를 1번부터 N번으로 매길 때, 어떠한 기차에 대하여 M개의 명령이 주어진다.
명령의 종류는 4가지로 다음과 같다.
- 1 i x : i번째 기차에(1 ≤ i ≤ N) x번째 좌석에(1 ≤ x ≤ 20) 사람을 태워라. 이미 사람이 타있다면 , 아무런 행동을 하지 않는다.
- 2 i x : i번째 기차에 x번째 좌석에 앉은 사람은 하차한다. 만약 아무도 그자리에 앉아있지 않았다면, 아무런 행동을 하지 않는다.
- 3 i : i번째 기차에 앉아있는 승객들이 모두 한칸씩 뒤로간다. k번째 앉은 사람은 k+1번째로 이동하여 앉는다. 만약 20번째 자리에 사람이 앉아있었다면 그 사람은 이 명령 후에 하차한다.
- 4 i : i번째 기차에 앉아있는 승객들이 모두 한칸씩 앞으로간다. k번째 앉은 사람은 k-1 번째 자리로 이동하여 앉는다. 만약 1번째 자리에 사람이 앉아있었다면 그 사람은 이 명령 후에 하차한다.
M번의 명령 후에 1번째 기차부터 순서대로 한 기차씩 은하수를 건너는데 조건이 있다.
기차는 순서대로 지나가며 기차가 지나갈 때 승객이 앉은 상태를 목록에 기록하며 이미 목록에 존재하는 기록이라면 해당 기차는 은하수를 건널 수 없다.
예를 들면, 다음 그림을 예로 들었을 때, 1번째 기차와 같이 승객이 앉은 상태는 기록되지 않았기 때문에 은하수를 건널 수있다. 2번째 기차와 같은 상태도 기록되지 않았기 때문에 2번째 기차도 은하수를 건널 수 있다. 3번째 기차는 1번째 기차와 승객이 앉은 상태가 같으므로 은하수를 건널 수 없다.
처음에 주어지는 기차에는 아무도 사람이 타지 않는다.
은하수를 건널 수 있는 기차의 수를 출력하시오.
입력
입력의 첫째 줄에 기차의 수 N(1 ≤ N ≤ 100000)과 명령의 수 M(1 ≤ M ≤ 100000)가 주어진다. 이후 두 번째 줄부터 M+1번째 줄까지 각 줄에 명령이 주어진다.
출력
은하수를 건널 수 있는 기차의 수를 출력하시오.
풀이 과정
연산의 종류를 보고 비트마스킹 기법으로 풀이할 수 있음을 떠올렸다.
- 1 i x : i번째 기차에(1 ≤ i ≤ N) x번째 좌석에(1 ≤ x ≤ 20) 사람을 태워라. 이미 사람이 타있다면 , 아무런 행동을 하지 않는다. ( x번째 비트에 1을 OR 연산 하라. 이미 x번째 비트가 1이면 아무것도 변화하지 않으므로. )
- 2 i x : i번째 기차에 x번째 좌석에 앉은 사람은 하차한다. 만약 아무도 그자리에 앉아있지 않았다면, 아무런 행동을 하지 않는다. ( x번째 비트를 제외한 모든 비트에 1을 AND 연산하고, x번째 비트에는 0을 AND 연산하여 x번째 비트만 0으로 만든다. 이미 x번째 비트가 0이면 아무것도 변화하지 않으므로. )
- 3 i : i번째 기차에 앉아있는 승객들이 모두 한칸씩 뒤로간다. k번째 앉은 사람은 k+1번째로 이동하여 앉는다. 만약 20번째 자리에 사람이 앉아있었다면 그 사람은 이 명령 후에 하차한다. ( 비트 Left Shift 연산을 하되 (1 << 20) - 1 을 AND 연산해주어 20개 비트만 남도록 자른다. )
- 4 i : i번째 기차에 앉아있는 승객들이 모두 한칸씩 앞으로간다. k번째 앉은 사람은 k-1 번째 자리로 이동하여 앉는다. 만약 1번째 자리에 사람이 앉아있었다면 그 사람은 이 명령 후에 하차한다. ( 비트 Right Shift 연산한다. )
기차의 상태가 정수로 관리되므로, 이전 기차와 값이 공통되는 기차는 제외하고 개수를 센다.
import sys
input = sys.stdin.readline
n, m = map(int, input().rstrip().split())
arr = [0 for _ in range(n)]
for _ in range(m):
order = list(map(int, input().rstrip().split()))
if order[0] == 1: arr[order[1]-1] |= (1 << (order[2] - 1))
elif order[0] == 2: arr[order[1]-1] &= (((1 << 20) - 1) - (1 << order[2] - 1))
elif order[0] == 3:
arr[order[1]-1] <<= 1
arr[order[1]-1] &= (1 << 20) - 1
else: arr[order[1]-1] >>= 1
S = set()
for a in arr: S.add(a)
print(len(S))
'-- 예전 기록 > BOJ' 카테고리의 다른 글
[ BOJ ] 2591 : 숫자카드 ( GOLD 5 ) / Python (0) | 2024.02.17 |
---|---|
[ BOJ ] 16918 : 봄버맨 ( SILVER 1 ) / Python (0) | 2024.02.17 |
[ BOJ ] 20365 : 블로그2 ( SILVER 3 ) / Python (0) | 2024.02.17 |
[ BOJ ] 12761 : 돌다리 ( SILVER 1 ) / Python (0) | 2024.02.15 |
[ BOJ ] 1058 : 친구 ( SILVER 2 ) / Python (0) | 2024.02.15 |