1부터 연속적으로 번호가 붙어있는 스위치들이 있다. 스위치는 켜져 있거나 꺼져있는 상태이다. <그림 1>에 스위치 8개의 상태가 표시되어 있다. ‘1’은 스위치가 켜져 있음을, ‘0’은 꺼져 있음을 나타낸다. 그리고 학생 몇 명을 뽑아서, 학생들에게 1 이상이고 스위치 개수 이하인 자연수를 하나씩 나누어주었다. 학생들은 자신의 성별과 받은 수에 따라 아래와 같은 방식으로 스위치를 조작하게 된다.
남학생은 스위치 번호가 자기가 받은 수의 배수이면, 그 스위치의 상태를 바꾼다. 즉, 스위치가 켜져 있으면 끄고, 꺼져 있으면 켠다. <그림 1>과 같은 상태에서 남학생이 3을 받았다면, 이 학생은 <그림 2>와 같이 3번, 6번 스위치의 상태를 바꾼다.
여학생은 자기가 받은 수와 같은 번호가 붙은 스위치를 중심으로 좌우가 대칭이면서 가장 많은 스위치를 포함하는 구간을 찾아서, 그 구간에 속한 스위치의 상태를 모두 바꾼다. 이때 구간에 속한 스위치 개수는 항상 홀수가 된다.

예를 들어 <그림 2>에서 여학생이 3을 받았다면, 3번 스위치를 중심으로 2번, 4번 스위치의 상태가 같고 1번, 5번 스위치의 상태가 같으므로, <그림 3>과 같이 1번부터 5번까지 스위치의 상태를 모두 바꾼다. 만약 <그림 2>에서 여학생이 4를 받았다면, 3번, 5번 스위치의 상태가 서로 다르므로 4번 스위치의 상태만 바꾼다.


입력으로 스위치들의 처음 상태가 주어지고, 각 학생의 성별과 받은 수가 주어진다. 학생들은 입력되는 순서대로 자기의 성별과 받은 수에 따라 스위치의 상태를 바꾸었을 때, 스위치들의 마지막 상태를 출력하는 프로그램을 작성하시오.
첫째 줄에는 스위치 개수가 주어진다. 스위치 개수는 100 이하인 양의 정수이다. 둘째 줄에는 각 스위치의 상태가 주어진다. 켜져 있으면 1, 꺼져있으면 0이라고 표시하고 사이에 빈칸이 하나씩 있다. 셋째 줄에는 학생수가 주어진다. 학생수는 100 이하인 양의 정수이다. 넷째 줄부터 마지막 줄까지 한 줄에 한 학생의 성별, 학생이 받은 수가 주어진다. 남학생은 1로, 여학생은 2로 표시하고, 학생이 받은 수는 스위치 개수 이하인 양의 정수이다. 학생의 성별과 받은 수 사이에 빈칸이 하나씩 있다.
스위치의 상태를 1번 스위치에서 시작하여 마지막 스위치까지 한 줄에 20개씩 출력한다. 예를 들어 21번 스위치가 있다면 이 스위치의 상태는 둘째 줄 맨 앞에 출력한다. 켜진 스위치는 1, 꺼진 스위치는 0으로 표시하고, 스위치 상태 사이에 빈칸을 하나씩 둔다.
8
0 1 0 1 0 0 0 1
2
1 3
2 3
1 0 0 0 1 1 0 1
코테로 본 문제라 이미 2번이나 복습을 해서 정답 후 풀이 과정을 적어보겠다(2번을 풀었어도 헤깔리는건 매한가지 ㅠㅠ)
import sys
def read_input():
try:
# Try to read from a file
with open('input.txt', 'r') as f:
data = f.read().split()
except FileNotFoundError:
# If the file is not found, read from standard input
data = sys.stdin.read().split()
return data
data = read_input()
# 스위치 개수
switch_count = int(data[0])
# 스위치 상태(정수)
switch_status = list(map(int, data[1:switch_count+1]))
# 학생 수
students = int(data[switch_count+1])
# 학생 정보(성별, 받은 수)
student_info = list(map(int, data[switch_count+2:switch_count+2+(2*students)]))
# 스위치 온/오프
def switch_toggle(i ,switch_status):
switch_status[i] = 1 - switch_status[i]
# 학생 정보 반영한 스위치 결과
def student_to_switch(switch_status, student_info):
# i는 0부터 시작
for i in range(0, len(student_info), 2):
gender = student_info[i]
#실제 학생이 받은 번호
switch_number = student_info[i+1]
switch_index = switch_number - 1
# 남학생일 때 = 해당 스위치의 배수들은 전부 toggle처리
if gender == 1:
# number 인덱스부터 number+1 = 실제 받은 자연수 만큼 간격을 벌려주면서 스위치 개수범위 안에서 j로 반복 시킨다
for j in range(switch_index, len(switch_status), switch_number):
switch_toggle(j, switch_status)
# else처리해도 되지만 가독성을 위해 elif
elif gender == 2:
#기준점은 여학생 수의 인덱스
left_start_index = switch_index
right_start_index = switch_index
# 여학생 뽑은 숫자 기준 좌우 정렬일때 0과 len(switch_status)-1 범위 인경우는 만약 left가 1일때 -1을 해줘서 0까지 가게 되는 로직이므로(물론 조건이 충족될 때) 해당 범위까지 설정해줘야 한다
while left_start_index > 0 and right_start_index < len(switch_status)-1:
if switch_status[left_start_index-1] != switch_status[right_start_index + 1]:
break
left_start_index -= 1
right_start_index += 1
for i in range(left_start_index, right_start_index + 1):
switch_toggle(i, switch_status)
def print_switch_status(switch_status):
for i in range(0, len(switch_status), 20):
# 숫자 리스트 공백으로 구분된 형태 출력
result = ' '.join(map(str, switch_status[i:i+20]))
print(result)
# 스위치 상태를 업데이트
student_to_switch(switch_status, student_info)
# 스위치 상태를 출력
print_switch_status(switch_status)
일단 입력값 받아오는 방식을 cph, 터미널 디버깅 둘 다 활용하기 위해, 예외처리한 data 받아오기를 구현하였고,
VS code에서 cph와 터미널 디버깅 둘다 사용할 수 있는 처리 방법(sys)
한번에 받아온 정보로 스위치 개수/상태/학생 수/학생정보를 구분지어줬다.
def switch_toggle(i ,switch_status):
switch_status[i] = 1 - switch_status[i]
해당 코드로 스위치 관련해서 i번째 인덱스에 대한 출력 값을 0이나 1을 1에서 0으로 뒤집어주는 함수
def student_to_switch(switch_status, student_info):
# i는 0부터 시작
for i in range(0, len(student_info), 2):
gender = student_info[i]
#실제 학생이 받은 번호
switch_number = student_info[i+1]
switch_index = switch_number - 1
# 남학생일 때 = 해당 스위치의 배수들은 전부 toggle처리
if gender == 1:
# number 인덱스부터 number+1 = 실제 받은 자연수 만큼 간격을 벌려주면서 스위치 개수범위 안에서 j로 반복 시킨다
for j in range(switch_index, len(switch_status), switch_number):
switch_toggle(j, switch_status)
# else처리해도 되지만 가독성을 위해 elif
elif gender == 2:
#기준점은 여학생 수의 인덱스
left_start_index = switch_index
right_start_index = switch_index
# 여학생 뽑은 숫자 기준 좌우 정렬일때 0과 len(switch_status)-1 범위 인경우는 만약 left가 1일때 -1을 해줘서 0까지 가게 되는 로직이므로(물론 조건이 충족될 때) 해당 범위까지 설정해줘야 한다
while left_start_index > 0 and right_start_index < len(switch_status)-1:
if switch_status[left_start_index-1] != switch_status[right_start_index + 1]:
break
left_start_index -= 1
right_start_index += 1
for i in range(left_start_index, right_start_index + 1):
switch_toggle(i, switch_status)
굉장히 숫자 한두개 차이, 그리고 코드 내용 구성, 특히 여학생 관련 처리로 골머리를 앓았었는데 분석해보자면,
일단 함수는 스위치 상태와 학생 정보를 헤깔리지 않게 변수명 그대로 인자로 받아와 내부에서 처리를 해주었으며,
# i는 0부터 시작
for i in range(0, len(student_info), 2):
gender = student_info[i]
#실제 학생이 받은 번호
switch_number = student_info[i+1]
switch_index = switch_number - 1
여기서 학생 정보를 성별과 받은 번호로 구분지어 줬다.
이 과정에서 for문의 간격은 2로 세팅할 수 밖에 없었던게, 한 학생의 정보는 2개씩 들어있어서 2 간격으로 처리하였다.
# 남학생일 때 = 해당 스위치의 배수들은 전부 toggle처리
if gender == 1:
# number 인덱스부터 number+1 = 실제 받은 자연수 만큼 간격을 벌려주면서 스위치 개수범위 안에서 j로 반복 시킨다
for j in range(switch_index, len(switch_status), switch_number):
switch_toggle(j, switch_status)
남학생일 땐, 받을 수의 배수에 대해 전부 toggle처리 해야하므로,
if문과 for문으로 범위, 간격 설정해서 switch_toggle 함수로 스위치를 처리해주었다.
여학생처리가 드럽게 헤깔렸는데
elif gender == 2:
#기준점은 여학생 수의 인덱스
left_start_index = switch_index
right_start_index = switch_index
# 여학생 뽑은 숫자 기준 좌우 정렬일때 0과 len(switch_status)-1 범위 인경우는 만약 left가 1일때 -1을 해줘서 0까지 가게 되는 로직이므로(물론 조건이 충족될 때) 해당 범위까지 설정해줘야 한다
while left_start_index > 0 and right_start_index < len(switch_status)-1:
if switch_status[left_start_index-1] != switch_status[right_start_index + 1]:
break
left_start_index -= 1
right_start_index += 1
for i in range(left_start_index, right_start_index + 1):
switch_toggle(i, switch_status)
if문으로 gender==2일 경우에만 여학생 관련된 부분이고,
start인덱스를 기본값으로 왜 switch_index를 세팅해야하는지 처음엔 이해가 안갔다.
그러나 코드를 구현하다보니 해당 번호보단, 그 번호가 위치한 인덱스에 접근해서 숫자를 바꿔줘야 하므로, 초기 값은 인덱스 값으로 세팅을 해야했고,
처음부터 -1이나 +1처리해서 기본값을 세팅해도 되었는데, 그렇게 하다보니
아래 구현 코드에서 조금 더 복잡한 코드, 가독성이 떨어지는 코드가 완성되었다.
그래서 아래 while문을 보면 >0 이나 <len(switch_status)-1로 정해놨는데 0번째 인덱스까지 검증해야하는데 왜 저렇게 조건을 뒀는지 내부 while로직을 살펴보면 무조건 참일때 left엔 -1인덱스, right엔 +1인덱스를 더해주므로, 해당 범위가 맞았다.
근데 여기서 범위에 대해서 왜 >0일까가 너무 이해가 안가서 엄청 많은 시간을 투자한 끝에 드디어 해결했다
일단 내가 이해가 안간건 좌측 인덱스가0일때 기준 좌우값 비교를 해줘야하는데 그걸 안한 것이다.
그래서 고민한끝에 드디어 만족스러운 세팅을 하였는데,
elif gender == 2:
left_number_index = number_index
right_number_index = number_index
while left_number_index >= 0 and right_number_index < len(switch_state) and switch_state[left_number_index] == switch_state[right_number_index]:
if switch_state[left_number_index] != switch_state[right_number_index]:
break
left_number_index -= 1
right_number_index += 1
left_number_index += 1
right_number_index -= 1
이렇게하면 인덱스가 0일때까지도 분석해서 좌우 값이 같은지 확인할 수 있고 while문 마지막에 좌측 인덱스를 음수처리해도? while문 이후 1더해주고 빼는 과정을 통해 해당 인덱스를 잘 찾아가므로,
이제서야 남에게 설명할 수 있을 정도로 별것도아닌걸 범위때문에 개고생했다 2일 동안 ;;;;
멍청멍청~

for i in range(left_start_index, right_start_index + 1):
switch_toggle(i, switch_status)
그다음엔 뭐 반복문돌려서 좌측인덱스부터 우측인덱스까지 토글 시킨다~
def print_switch_status(switch_status):
for i in range(0, len(switch_status), 20):
# 숫자 리스트 공백으로 구분된 형태 출력
result = ' '.join(map(str, switch_status[i:i+20]))
print(result)
20개 넘어가면 아랫줄에 출력하라 했으므로,
함수로 반복문 돌리면서 20개 간격 즉 21개부터는 아랫줄에 출력되도록 i가 0이면
0~19까지, i가1이면 20부터~ 이런식으로 출력된다
result에 담는 범위도 i부터i+20까지~
그렇게 최종적으로
# 스위치 상태를 업데이트
student_to_switch(switch_status, student_info)
# 스위치 상태를 출력
print_switch_status(switch_status)
이렇게 함수를 두번 출력하면 원하는 결과값을 얻을 수 있다~
참 한문제로 고생했다 머리에 많이 오랫동안 기억했으면~~