매일 아침 9시에 학교에서 측정한 온도가 어떤 정수의 수열로 주어졌을 때, 연속적인 며칠 동안의 온도의 합이 가장 큰 값을 알아보고자 한다.

예를 들어, 아래와 같이 10일 간의 온도가 주어졌을 때,

3 -2 -4 -9 0 3 7 13 8 -3

모든 연속적인 이틀간의 온도의 합은 아래와 같다.

 

이때, 온도의 합이 가장 큰 값은 21이다.

또 다른 예로 위와 같은 온도가 주어졌을 때, 모든 연속적인 5일 간의 온도의 합은 아래와 같으며,

 

이때, 온도의 합이 가장 큰 값은 31이다.

매일 측정한 온도가 정수의 수열로 주어졌을 때, 연속적인 며칠 동안의 온도의 합이 가장 큰 값을 계산하는 프로그램을 작성하시오.

 

입력

첫째 줄에는 두 개의 정수 N과 K가 한 개의 공백을 사이에 두고 순서대로 주어진다. 첫 번째 정수 N은 온도를 측정한 전체 날짜의 수이다. N은 2 이상 100,000 이하이다. 두 번째 정수 K는 합을 구하기 위한 연속적인 날짜의 수이다. K는 1과 N 사이의 정수이다. 둘째 줄에는 매일 측정한 온도를 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 수들은 모두 -100 이상 100 이하이다.

출력

첫째 줄에는 입력되는 온도의 수열에서 연속적인 K일의 온도의 합이 최대가 되는 값을 출력한다.

 

코드

import sys
input = sys.stdin.readline

N, K = map(int, input().split())
temp = list(map(int, input().split()))
sum = []

for i in range(N-K):
    x = 0
    for j in range(K):
        x += temp[i+j]
    sum.append(x)
    

print(max(sum))

 

항상 왜 이렇게 쉽게 풀리지 ?  싶으면 역시나 시간초과가 뜬다.

 

수정코드

import sys
input = sys.stdin.readline

N, K= map(int, input().split())
temp = list(map(int, input().split()))

result = []
result.append(sum(temp[:K]))

for i in range(N-K):
    result.append(result[i]-temp[i]+temp[i+K])

print(max(result))

 

sum 연산 횟수를 줄이기 위해 이전 결과값을 어느정도 이용할 수 있도록 코드를 수정하였다.

이전 결과값에서 맨 앞 숫자를 빼고 다음 첫 숫자를 더하면 다음 결과값이 된다.

 

 

2108번: 통계학

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

www.acmicpc.net

수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

출력

첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.

둘째 줄에는 중앙값을 출력한다.

셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.

넷째 줄에는 범위를 출력한다.

 

코드

from collections import Counter

n = int(input())
num = list(int(input()) for _ in range(n))

print(round(sum(num) / n))   #평균

num.sort()
print(num[n//2])   # 중앙값

cnt = sorted(Counter(num).items(), key = lambda x: (-x[1], x[0])) #최빈값
if n == 1:
    print(num[0])
else:
    if cnt[0][1] == cnt[1][1]:
        print(cnt[1][0])
    else:
        print(cnt[0][0])


print(max(num)-min(num))  #범위

 

로 했는데 시간초과가 떴다.

 

Statistics 라이브러리를 import 해서 풀어봤다. statistics를 이용하면 산술평균, 중앙값, 범위는 쉽게 구할 수 있다.

import sys
import statistics as st
from collections import Counter

input = sys.stdin.readline
n = int(input())
num = [int(input()) for _ in range(n)]

print(round(st.mean(num))) # 평균
print(st.median(num)) # 중앙값

cnt = sorted(Counter(num).most_common(), key = lambda x: (-x[1], x[0])) #최빈값
if n ==1 :
    print(num[0])
else:
    if cnt[0][1] == cnt[1][1]:
        print(cnt[1][0])
    else:
        print(cnt[0][0])

print(max(num) - min(num)) # 범위

 

요리조리 해봐도 시간초과가 떴다.

결국 import sys를 해서 input = sys.stdin.readline 을 작성해서 코드를 돌려봤는데 정답입니다 !! 가 떴다...

오늘의 가르침

귀찮더라도 import sys 를 잊지말고 쓰자..

 

NEW

 

 

여러분도 알다시피 여러분의 프린터 기기는 여러분이 인쇄하고자 하는 문서를 인쇄 명령을 받은 ‘순서대로’, 즉 먼저 요청된 것을 먼저 인쇄한다. 여러 개의 문서가 쌓인다면 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 이하의 정수이고, 중요도가 같은 문서가 여러 개 있을 수도 있다.

출력

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

 

코드

from collections import deque

k = int(input())

for i in range(k):
    n,m = map(int, input().split())
    queue = deque(map(int, input().split()))
    cnt = 0
    while queue:
        best = max(queue)
        front = queue.popleft()
        m -= 1

        if best == front:
            cnt += 1
            if m < 0:
                print(cnt)
                break
        
        else:
            queue.append(front)
            if m < 0:
                m = len(queue)-1

 

프린터는 FIFO(First In First Out) 선입 선출의 구조로 문서를 출력

m번째 숫자를 내 숫자라고 했을 때, 내 숫자가 max(queue)가 될 때까지 검사를 실행하면 된다.

만약 가장 큰 숫자가 아니면 맨 끝에 append하고 인덱스(m)도 마지막으로 수정한다.

 

NEW

파이썬의 'deque(Double Ended Queue)는 양쪽 끝에서 빠르게 삽입과 삭제를 할 수 있는 자료구조이다.

'deque'는 파이썬의 내장 모듈인 'collections'에 포함되어 있다,

 

일반적인 리스트와 달리 'deque'는 양쪽 끝에서의 연산이 O(1) 시간에 수행된다. 따라서 리스트의 맨 앞이나 맨 끝에서 요소를 추가하거나 제거할 때 매우 효율적이다.

큐나 스택의 기능을 모두 수행할 수 있다.

deque는 생성할 때 고정된 크기를 지정할 수 있다. 크기를 지정하면 deque에 추가 요소가 해당 크기를 초과할 경우, 반대쪽 끝에서 요소가 제거된다.

리스트와 유사하게 deque도 슬라이싱을 통해 요소를 가져올 수 있다.

append(), appendleft(), pop(), popleft()

 

1748번: 수 이어 쓰기 1

첫째 줄에 N(1 ≤ N ≤ 100,000,000)이 주어진다.

www.acmicpc.net

1부터 N까지의 수를 이어서 쓰면 다음과 같이 새로운 하나의 수를 얻을 수 있다.

1234567891011121314151617181920212223...

이렇게 만들어진 새로운 수는 몇 자리 수일까? 이 수의 자릿수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 N(1 ≤ N ≤ 100,000,000)이 주어진다.

 

출력

첫째 줄에 새로운 수의 자릿수를 출력한다.

 

코드

n = int(input())
answer = 0

for i in range(1, n+1):
    answer += len(str(i))

print(answer)

 
n까지의 숫자를 문자로 바꿔 글자수를 더하는 코드를 짰는데 시간초과가 떴다.
다른 접근으로 생각해보면
n이 한자리수라면 최대치는 1*9, 두자리수라면 2*90, 세자리수라면 3*900이다.
n의 자릿수-1번까지 위 규칙의 수를 더하고 length*(n-10**(length-1)+1)을 더해주면 된다.
 

수정코드

n = int(input())
answer = 0
length = len(str(n))

if length == 1:
    answer = int(n)
else:
    answer = 9
    for i in range(2,length):
        answer += i*(9*10**(i-1))
    answer += length*(n-10**(length-1)+1)

print(answer)

문제

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

1620번: 나는야 포켓몬 마스터 이다솜

첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면

www.acmicpc.net

입력

첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면 물어봐도 괜찮아. 나는 언제든지 질문에 답해줄 준비가 되어있어.

둘째 줄부터 N개의 줄에 포켓몬의 번호가 1번인 포켓몬부터 N번에 해당하는 포켓몬까지 한 줄에 하나씩 입력으로 들어와. 포켓몬의 이름은 모두 영어로만 이루어져있고, 또, 음... 첫 글자만 대문자이고, 나머지 문자는 소문자로만 이루어져 있어. 아참! 일부 포켓몬은 마지막 문자만 대문자일 수도 있어. 포켓몬 이름의 최대 길이는 20, 최소 길이는 2야. 그 다음 줄부터 총 M개의 줄에 내가 맞춰야하는 문제가 입력으로 들어와. 문제가 알파벳으로만 들어오면 포켓몬 번호를 말해야 하고, 숫자로만 들어오면, 포켓몬 번호에 해당하는 문자를 출력해야해. 입력으로 들어오는 숫자는 반드시 1보다 크거나 같고, N보다 작거나 같고, 입력으로 들어오는 문자는 반드시 도감에 있는 포켓몬의 이름만 주어져. 그럼 화이팅!!!

출력

첫째 줄부터 차례대로 M개의 줄에 각각의 문제에 대한 답을 말해줬으면 좋겠어!!!. 입력으로 숫자가 들어왔다면 그 숫자에 해당하는 포켓몬의 이름을, 문자가 들어왔으면 그 포켓몬의 이름에 해당하는 번호를 출력하면 돼. 그럼 땡큐~

이게 오박사님이 나에게 새로 주시려고 하는 도감이야. 너무 가지고 싶다ㅠㅜ. 꼭 만점을 받아줬으면 좋겠어!! 파이팅!!!

 

코드

n,m = map(int, input().split())

by_name = dict()
by_num = dict()

for i in range(1, n+1):
    pokemon = input()
    by_name[pokemon] = i
    by_num[i] = pokemon

for _ in range(m):
    x = input()
    if x.isdigit():
        print(by_num[int(x)])
    else:
        print(by_name[x])

 

이름을 키값으로 하는 딕셔너리 하나와 포켓몬번호를 키값으로 하는 딕셔너리 하나를 생성한다.

각각의 딕셔너리에 (이름, 번호),(번호, 이름)를 저장한다.

m번 만큼 문제를 입력 받고, 입력이 숫자이면( isdigit()사용) by_num 딕셔너리를 이용하고, 문자이면 by_name 딕셔너리를 이용하여 value값을 출력한다.

 

처음에 딕셔너리를 이용하여 문제를 풀어야겠다는 생각까지 했다.

하지만 딕셔너리 하나에 (번호, 이름)쌍으로 저장하고 입력값이 번호와 같으면 이름을 출력하고, 반대면 번호를 출력하도록 코드를 짰는데 문제가 문자인 경우에만 출력이 됐다. 처음 if문에서 제대로 조건문이 적용되지 않아서 elif 문만 실행된 것 같다.

딕셔너리 하나로도 실행되는 코드도 다시 짜보았다.

import sys
input = sys.stdin.readline

n,m = map(int, input().split())

my_dict = {}

for i in range(1, n+1):
    a = input().rstrip()
    my_dict[i] = a
    my_dict[a] = i

for _ in range(m):
    x = input().rstrip()
    if x.isdigit():
        print(my_dict[int(x)])
    else:
        print(my_dict[x])

 
하나의 딕셔너리에 (이름, 번호) , (번호, 이름) 을 각각 저장하면 된다.

문제

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

 

김지민은 N명이 참가하는 스타 토너먼트에 진출했다. 토너먼트는 다음과 같이 진행된다. 일단 N명의 참가자는 번호가 1번부터 N번까지 배정받는다. 그러고 난 후에 서로 인접한 번호끼리 스타를 한다. 이긴 사람은 다음 라운드에 진출하고, 진 사람은 그 라운드에서 떨어진다. 만약 그 라운드의 참가자가 홀수명이라면, 마지막 번호를 가진 참가자는 다음 라운드로 자동 진출한다. 다음 라운드에선 다시 참가자의 번호를 1번부터 매긴다. 이때, 번호를 매기는 순서는 처음 번호의 순서를 유지하면서 1번부터 매긴다. 이 말은 1번과 2번이 스타를 해서 1번이 진출하고, 3번과 4번이 스타를 해서 4번이 진출했다면, 4번은 다음 라운드에서 번호 2번을 배정받는다. 번호를 다시 배정받은 후에 한 명만 남을 때까지 라운드를 계속 한다.

마침 이 스타 대회에 임한수도 참가했다. 김지민은 갑자기 스타 대회에서 우승하는 욕심은 없어지고, 몇 라운드에서 임한수와 대결하는지 궁금해졌다. 일단 김지민과 임한수는 서로 대결하기 전까지 항상 이긴다고 가정한다. 1 라운드에서 김지민의 번호와 임한수의 번호가 주어질 때, 과연 김지민과 임한수가 몇 라운드에서 대결하는지 출력하는 프로그램을 작성하시오.

입력

첫째 줄에 참가자의 수 N과 1 라운드에서 김지민의 번호와 임한수의 번호가 순서대로 주어진다. N은 2보다 크거나 같고, 100,000보다 작거나 같은 자연수이고, 김지민의 번호와 임한수의 번호는 N보다 작거나 같은 자연수이고, 서로 다르다.

 

출력

첫째 줄에 김지민과 임한수가 대결하는 라운드 번호를 출력한다. 만약 서로 대결하지 않을 때는 -1을 출력한다.

 

코드

n, a, b = map(int, input().split())

cnt = 0
while a != b:
    a -= a//2
    b -= b//2
    cnt += 1
print(cnt)

3번과 4번이 붙어서

3번이 이겨서 올라간다고 했을 때 그 다음 라운드 번호는 3-3//2 인 2번이다.

4번이 이겨서 올라간다고 해도 그 다음 라운드 번호는 4-4//2인 2번이다.

만약 김지민과 임한수의 다음 라운드 번호가 같다면 그 둘은 그 전라운드에서 서로 대결한 것이다.

 

처음에 코드 짤 때 이런 접근이 아니라 또 문제 곧이곧대로 토너먼트 진행방식의 코드를 통째로 짰다.

또 다시 시간초과가 떴다.. 코드를 맞게 짠 건지도 잘 모르겠지만...

만약 코드가 너무 복잡해지거나 시간초과가 뜬다면 다른 접근, 더 쉬운 접근도 생각해보기 

 

+ Recent posts