728x90

문제

선영이는 주말에 할 일이 없어서 새로운 언어 AC를 만들었다. AC는 정수 배열에 연산을 하기 위해 만든 언어이다. 이 언어에는 두 가지 함수 R(뒤집기)과 D(버리기)가 있다.

함수 R은 배열에 있는 수의 순서를 뒤집는 함수이고, D는 첫 번째 수를 버리는 함수이다. 배열이 비어있는데 D를 사용한 경우에는 에러가 발생한다.

함수는 조합해서 한 번에 사용할 수 있다. 예를 들어, "AB"는 A를 수행한 다음에 바로 이어서 B를 수행하는 함수이다. 예를 들어, "RDD"는 배열을 뒤집은 다음 처음 두 수를 버리는 함수이다.

배열의 초기값과 수행할 함수가 주어졌을 때, 최종 결과를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. T는 최대 100이다.

각 테스트 케이스의 첫째 줄에는 수행할 함수 p가 주어진다. p의 길이는 1보다 크거나 같고, 100,000보다 작거나 같다.

다음 줄에는 배열에 들어있는 수의 개수 n이 주어진다. (0 ≤ n ≤ 100,000)

다음 줄에는 [x1,...,xn]과 같은 형태로 배열에 들어있는 정수가 주어진다. (1 ≤ xi ≤ 100)

전체 테스트 케이스에 주어지는 p의 길이의 합과 n의 합은 70만을 넘지 않는다.

출력

각 테스트 케이스에 대해서, 입력으로 주어진 정수 배열에 함수를 수행한 결과를 출력한다. 만약, 에러가 발생한 경우에는 error를 출력한다.

코드 1

import sys
from collections import deque
t = int(sys.stdin.readline())

for i in range(t):
    p = list(sys.stdin.readline().rstrip())
    n = int(sys.stdin.readline())
    arr = sys.stdin.readline()[1:-2].rstrip().split(",")

    if n ==0:
        q = deque()
    else:
        q = deque(arr)

    rev = 0
    flag = 0 #error 인지 확인

    for j in p:
        if j=="R":
            rev+=1
        elif j== "D":
            if len(q)==0:
                print("error")
                flag = 1
                break
            else:
                if rev % 2 ==0:
                    q.popleft()
                else:
                    q.pop()
    if flag == 0:
        if rev % 2 ==0:
            print("["+",".join(q)+"]")
        else:
            q.reverse()
            print("[" + ",".join(q) + "]")

풀이 1

입력을 [1,2,3,4] 이렇게 받으니, 아래와 같이 슬라이싱 해서 입력받아야 한다.

arr = sys.stdin.readline()[1:-2].rstrip().split(",")

reverse() 연산과 popleft() 연산이 필요한 것을 보아 deque 라이브러리를 사용해서 을 구현했다.

하지만 R이 나올 때마다, reverse()연산을 했더니 시간 초과가 났다.

 

생각을 더 해보면, R은 짝수이면 뒤집기를 안한 것 과 같아서 홀수 일 때만 뒤집으면 된다.

또한, R이 짝수 이면 뒤집기를 안한 것과 같으니 맨 처음의 원소를 삭제하는 popleft() 연산을 하면 되고, 

R이 홀수 이면 맨 뒤에 원소를 삭제하는 것과 같아서 pop()연산을 한다.

 

flag 변수는 error 임을 체크하는 변수로 쓰였고 최종적으로 R이 홀수 일 때만 출력 전에 reverse() 연산을 해준다.

코드 2

import sys

t = int(sys.stdin.readline())

for i in range(t):
    p = sys.stdin.readline().rstrip()
    n = int(sys.stdin.readline())
    arr = sys.stdin.readline()[1:-2].rstrip().split(",")
    p = p.replace("RR","")

    rev = 0
    f,b = 0,0
    flag = 0 #error 인지 확인

    for j in p:
        if j=="R":
            rev+=1
        elif j== "D":
            if rev % 2 ==0:
                f+=1
            else:
                b+=1
    if f+b <= n:
        arr = arr[f:n-b]
        if rev % 2 ==0:
            print("["+",".join(arr)+"]")
        else:
            print("[" + ",".join(arr[::-1]) + "]")
    else:
        print("error")

풀이 2

덱 라이브러리를 사용하지 않고 문자열 슬라이싱으로 풀이하는 방법이다.

우선, 풀이1의 방법과 비슷한 점이 있다.

R이 짝수면 앞에서부터 제거 (f+=1 표시)

R이 홀수면 뒤에서부터 제거 (b+=1 표시)

그리고 RR이 연속해 있으면 ""으로 교체해 제거한다.

 

f+b의 합이 n보다 크면 error 출력하고

이하이면 문자열을 f부터 n-b까지 저장하고 reverse 연산을 한다.

 

python에서는 리스트를 뒤집는 방법이 reverse()연산 말고도

list[::-1] 방법이 있다.

728x90

문제

직선으로 되어있는 도로의 한 편에 가로수가 임의의 간격으로 심어져있다. KOI 시에서는 가로수들이 모두 같은 간격이 되도록 가로수를 추가로 심는 사업을 추진하고 있다. KOI 시에서는 예산문제로 가능한 한 가장 적은 수의 나무를 심고 싶다.

편의상 가로수의 위치는 기준점으로 부터 떨어져 있는 거리로 표현되며, 가로수의 위치는 모두 양의 정수이다.

예를 들어, 가로수가 (1, 3, 7, 13)의 위치에 있다면 (5, 9, 11)의 위치에 가로수를 더 심으면 모든 가로수들의 간격이 같게 된다. 또한, 가로수가 (2, 6, 12, 18)에 있다면 (4, 8, 10, 14, 16)에 가로수를 더 심어야 한다.

심어져 있는 가로수의 위치가 주어질 때, 모든 가로수가 같은 간격이 되도록 새로 심어야 하는 가로수의 최소수를 구하는 프로그램을 작성하라. 단, 추가되는 나무는 기존의 나무들 사이에만 심을 수 있다.

입력

첫째 줄에는 이미 심어져 있는 가로수의 수를 나타내는 하나의 정수 N이 주어진다(3 ≤ N ≤ 100,000). 둘째 줄부터 N개의 줄에는 각 줄마다 심어져 있는 가로수의 위치가 양의 정수로 주어지며, 가로수의 위치를 나타내는 정수는 1,000,000,000 이하이다. 가로수의 위치를 나타내는 정수는 모두 다르다.

출력

모든 가로수가 같은 간격이 되도록 새로 심어야 하는 가로수의 최소수를 첫 번째 줄에 출력한다.

코드

import math
import sys
n = int(sys.stdin.readline())
tree = []
bet_tree = []
result = 0

#가로수 저장
for i in range(n):
    tree.append(int(sys.stdin.readline().rstrip()))
#가로수 간격 저장
for i in range(n-1):
    bet_tree.append(tree[i+1]-tree[i])

#가로수 간격의 최대공약수 찾기
gcd = bet_tree[0]
for i in range(1,len(bet_tree)):
    gcd = math.gcd(gcd,bet_tree[i])

#가로수 간격 //최대공약수 -1 의 합이 답
for i in range(len(bet_tree)):
    result += bet_tree[i] // gcd -1
print(result)

풀이

가로수 간격 / 가로수 사이의 간격의 최대공약수 -1 의 합이 정답이다.

728x90

문제

여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 Queue 자료구조에 쌓여서 FIFO - First In First Out - 에 따라 인쇄가 되게 된다. 하지만 상근이는 새로운 프린터기 내부 소프트웨어를 개발하였는데, 이 프린터기는 다음과 같은 조건에 따라 인쇄를 하게 된다.

  1. 현재 Queue의 가장 앞에 있는 문서의 ‘중요도’를 확인한다.
  2. 나머지 문서들 중 현재 문서보다 중요도가 높은 문서가 하나라도 있다면, 이 문서를 인쇄하지 않고 Queue의 가장 뒤에 재배치 한다. 그렇지 않다면 바로 인쇄를 한다.

예를 들어 Queue에 4개의 문서(A B C D)가 있고, 중요도가 2 1 4 3 라면 C를 인쇄하고, 다음으로 D를 인쇄하고 A, B를 인쇄하게 된다.

여러분이 할 일은, 현재 Queue에 있는 문서의 수와 중요도가 주어졌을 때, 어떤 한 문서가 몇 번째로 인쇄되는지 알아내는 것이다. 예를 들어 위의 예에서 C문서는 1번째로, A문서는 3번째로 인쇄되게 된다.

입력

첫 줄에 테스트케이스의 수가 주어진다. 각 테스트케이스는 두 줄로 이루어져 있다.

테스트케이스의 첫 번째 줄에는 문서의 개수 N(1 ≤ N ≤ 100)과, 몇 번째로 인쇄되었는지 궁금한 문서가 현재 Queue에서 몇 번째에 놓여 있는지를 나타내는 정수 M(0 ≤ M < N)이 주어진다. 이때 맨 왼쪽은 0번째라고 하자. 두 번째 줄에는 N개 문서의 중요도가 차례대로 주어진다. 중요도는 1 이상 9 이하의 정수이고, 중요도가 같은 문서가 여러 개 있을 수도 있다.

출력

각 테스트 케이스에 대해 문서가 몇 번째로 인쇄되는지 출력한다.

코드

import sys
T = int(sys.stdin.readline())
for i in range(T):
    n,m = map(int,sys.stdin.readline().split())
    q = list(map(int,sys.stdin.readline().split()))
    check = [0 for _ in range(n)]
    check[m] = 1
    cnt = 0

    while True:
        if q[0] == max(q):
            cnt+=1
            if check[0] != 1:
                del q[0]
                del check[0]
            else:
                print(cnt)
                break
        else:
            q.append(q[0])
            check.append(check[0])
            del q[0]
            del check[0]

풀이

필요한 것 

1) 우선순위 저장

2) 인덱스 저장

3) 찾아야 하는 인덱스 저장

4) 정답 cnt

 

리스트를 내림차순으로 정렬하는 과정에서 맨 처음 원소가 max값이면 cnt+=1 을 하고 리스트에서 꺼낸다. 

그 다음 max 값을 cnt+=1 하고 또 꺼낸다.

이 때, 원소 값을 꺼낼 때 인덱스를 체크하는 값도 같이 꺼낸다.

인덱스를 체크할 때, 찾고자 하는 인덱스면 끝낸다.

728x90

문제

요세푸스 문제는 다음과 같다.

1번부터 N번까지 N명의 사람이 원을 이루면서 앉아있고, 양의 정수 K(≤ N)가 주어진다. 이제 순서대로 K번째 사람을 제거한다. 한 사람이 제거되면 남은 사람들로 이루어진 원을 따라 이 과정을 계속해 나간다. 이 과정은 N명의 사람이 모두 제거될 때까지 계속된다. 원에서 사람들이 제거되는 순서를 (N, K)-요세푸스 순열이라고 한다. 예를 들어 (7, 3)-요세푸스 순열은 <3, 6, 2, 7, 5, 1, 4>이다.

N과 K가 주어지면 (N, K)-요세푸스 순열을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N과 K가 빈 칸을 사이에 두고 순서대로 주어진다. (1 ≤ K ≤ N ≤ 5,000)

출력

예제와 같이 요세푸스 순열을 출력한다.

코드

import sys
n,k = map(int,sys.stdin.readline().split())
q=[]
result = []
for i in range(1,n+1):
    q.append(i)

index = 0
while q:
    index += k-1
    if index >= len(q):
        index = index % len(q)

    result.append(q.pop(index))

print("<", ', '.join(str(i) for i in result),">",sep="")

풀이

index 는 삭제할 인덱스이고 계속 k만큼 더해주는데 배열의 인덱스이니까 k-1을 더해준다.

삭제할 인덱스가 큐 한바퀴를 돌면, 원 모양이니까 다시 인덱스가 돌아가야한다.

index = index % len(q)

이렇게 하면 돌아갈 수 있다.

 

마지막 출력은 join()함수를 써서 깔끔하게 작성한다.

', '.join(i for i in result)로 하면 result에 있는 i는 정수여서 str로 바꿔서 join해야한다.

이 때, "<", ">"를 쉼표로 같이 이어붙이면 공백이 발생한다.

정답은 공백을 제거해야하니까 sep = ""로 제거해준다.

 

728x90

문제

스택 (stack)은 기본적인 자료구조 중 하나로, 컴퓨터 프로그램을 작성할 때 자주 이용되는 개념이다. 스택은 자료를 넣는 (push) 입구와 자료를 뽑는 (pop) 입구가 같아 제일 나중에 들어간 자료가 제일 먼저 나오는 (LIFO, Last in First out) 특성을 가지고 있다.

1부터 n까지의 수를 스택에 넣었다가 뽑아 늘어놓음으로써, 하나의 수열을 만들 수 있다. 이때, 스택에 push하는 순서는 반드시 오름차순을 지키도록 한다고 하자. 임의의 수열이 주어졌을 때 스택을 이용해 그 수열을 만들 수 있는지 없는지, 있다면 어떤 순서로 push와 pop 연산을 수행해야 하는지를 알아낼 수 있다. 이를 계산하는 프로그램을 작성하라.

입력

첫 줄에 n (1 ≤ n ≤ 100,000)이 주어진다. 둘째 줄부터 n개의 줄에는 수열을 이루는 1이상 n이하의 정수가 하나씩 순서대로 주어진다. 물론 같은 정수가 두 번 나오는 일은 없다.

출력

입력된 수열을 만들기 위해 필요한 연산을 한 줄에 한 개씩 출력한다. push연산은 +로, pop 연산은 -로 표현하도록 한다. 불가능한 경우 NO를 출력한다.

코드

import sys
n = int(sys.stdin.readline())
stack = []
op = []
now = 1
possible = 1
for i in range(n):
    num = int(sys.stdin.readline())
    while now <= num:
        stack.append(now)
        op.append('+')
        now+=1

    if stack[-1] == num:
        stack.pop()
        op.append('-')
    else:
        possible = 0
if possible ==0:
    print("NO")
else:
    for i in op:
        print(i)

풀이

push()를 1부터 n까지 오름차순으로 해야한다.

그럼 입력값이 pop() 이 가능할 때까지 1부터 스택에 append() 해준다.

입력값이 pop()가능하면 pop()하고

불가능하면 NO 출력한다.

728x90

문제

두 개의 자연수를 입력받아 최대 공약수와 최소 공배수를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에는 두 개의 자연수가 주어진다. 이 둘은 10,000이하의 자연수이며 사이에 한 칸의 공백이 주어진다.

출력

첫째 줄에는 입력으로 주어진 두 수의 최대공약수를, 둘째 줄에는 입력으로 주어진 두 수의 최소 공배수를 출력한다.

코드1

import math
import sys
a,b = map(int,sys.stdin.readline().split())
print(math.gcd(a,b))
print(math.lcm(a,b))

풀이

python의 math라이브러리는

최대공약수 math.gcd(a,b)

최소공배수 math.lcm(a,b)를 제공한다.

코드2

import math
import sys
a,b = map(int,sys.stdin.readline().split())

def GCD(a,b):
    while b>0:
        a,b = b, a%b
    return a
    
def LCM(a,b):
    return int(a*b / GCD(a,b))
    
print(GCD(a,b))
print(LCM(a,b))

풀이

유클리드 호제법

최대공약수

a,b의 최대공약수는 a를 b로 나눈 나머지와 b의 최대공약수와 같다.

 

최소공배수는

a,b를 곱한 값을 a,b의 최대공약수로 나눈 값이 최소공배수이다.

 

외워잉

728x90

문제

M이상 N이하의 소수를 모두 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 M과 N이 빈 칸을 사이에 두고 주어진다. (1 ≤ M ≤ N ≤ 1,000,000) M이상 N이하의 소수가 하나 이상 있는 입력만 주어진다.

출력

한 줄에 하나씩, 증가하는 순서대로 소수를 출력한다.

코드

import sys
import math
n, m = map(int,sys.stdin.readline().split())
arr = [True for i in range(m+1)]
for i in range(2,int(math.sqrt(m))+1):
    if arr[i]==True:
        j=2
        while i*j <= m:
            arr[i*j] = False
            j+=1
for i in range(n,m+1):
    if i>1 and arr[i]:
        print(i)

풀이

데이터가 1,000,000 개 이하에서 여러 소수를 구하는 문제는 에라토스테네스의 체 알고리즘을 사용한다.

 

구해야하는 크기만큼의 True 배열을 만든다.

2부터 구해야하는 크기의 제곱근까지의 자기자신을 제외한 배수를 모두 False을 만든다.

2부터 2를 제외하고 4, 6, 8, 10... False

3부터 3을 제외하고 3, 6, 9, 12 ... False

...

이렇게 하고 True 인 것만 출력하면 소수만 나온다.

 

마지막에 출력 시, i는 2부터임을 주의하자.

 

+ Recent posts