https://www.acmicpc.net/problem/2460
train = {}
for i in range(10):
before, after = map(int,input().split())
if i == 0:
train[i] = after -before
else:
train[i] = train[i-1]-before+after
max_value = 0
max_name = ""
for k,v in train.items():
if v > max_value:
max_value = v
max_name = k
print(train[max_name])
이 코드는 다음과 같이 고쳐쓸 수 있다.
train = {}
current = 0
for i in range(10):
before, after = map(int, input().split())
current = current - before + after
train[i] = current # i번째 역 도착 시 사람 수 기록
print(max(train.values()))
배운점
dict.get(key, default) 정확한 활용의도: 딕셔너리에서 key가 없을 때도 에러 없이 값을 읽거나, 부재 시 기본값으로 대체.
형식: d.get(key, default)
key가 있으면: 그 값 반환key가 없으면: default 반환(딕셔너리에는 추가되지 않음)cnt = {}
for x in data:
cnt[x] = cnt.get(x, 0) + 1
bucket = {}
for k, v in pairs:
bucket.setdefault(k, []).append(v) # 또는 bucket[k] = bucket.get(k, []) + [v]
threshold = scores.get("alice", 0)
if threshold >= 10:
...
# ❌ '계산된 값'을 저장해야 하는데, 그 값을 key로 '조회'해버림
train[i] = train.get(after - before, 0)
train[i] = after - before가 맞다.max_value = max(train.values())
print(max_value)
max_key = max(train, key=train.get) # 값이 최대인 키
print(train[max_key], max_key)
best = [k for k, v in train.items() if v == max(train.values())]
# best에 동률 키 목록이 들어감
if train: # 빈 딕셔너리 방어
print(max(train.values()))
else:
print(0) # 문제 요구사항에 맞는 기본값 선택
train[i] = expr, 0 → (expr, 0) 튜플이 되어 TypeError 유발. 반드시 콤마 제거.train[i]를 채우기 전에 train[i]를 참조하지 말 것. 필요하면 current 같은 누적 변수를 사용.get과 대입 혼동:get)와 저장(대입 =)의 목적을 구분. 계산 결과를 키로 조회하지 말고 그대로 값에 대입..get은 조회 시 기본값 대체용이며 “계산값 저장”과는 무관하다.max(d.values()), 키도 필요하면 max(d, key=d.get)을 쓰면 된다.current로 갱신하고 필요 시만 딕셔너리에 기록하는 게 가장 깔끔하다.다음 단계로는 “동률 처리”, “음수 입력 방어”, “입력 개수 가변화” 같은 요구가 생길 때 위 패턴을 그대로 확장하면 된다.
https://www.acmicpc.net/problem/2577
import sys
input = sys.stdin.readline
answer = {}
target = 1
for _ in range(3):
num = int(input())
target *= num
for i in str(target):
answer[i] = answer.get(i,0) +1
for i in range(0,10):
answer[str(i)] = answer.get(str(i),0)
print(answer[str(i)])
이 소스코드는 다음과 같이 고쳐쓸 수 있다.
from collections import Counter
target = 1
for _ in range(3):
target *= int(input())
count = Counter(str(target)) # 각 숫자 등장 횟수 세기
for i in range(10):
print(count.get(str(i), 0))
배운점
(1) from collections import Counter를 잊지 말자 — 직접 딕셔너리 만들 필요 없다.
(2) num = int(input()) 대신 바로 target *= int(input())로 연산 단축 가능.
(3) cnt = Counter(str(target))로 각 숫자 빈도를 한 번에 구할 수 있다.
(4) cnt.get(str(i), 0)으로 없는 숫자도 0으로 안전하게 출력한다.
https://www.acmicpc.net/problem/2592
nums = {}
total = 0
for _ in range(10):
num = int(input())
total += num
nums[num] = nums.get(num, 0) + 1 # 등장 횟수 카운트
print(total // 10) # 평균
print(max(nums, key=nums.get)) # 최빈값
nums[num] = nums.get(num, 0) + 1
.get(key, default)는 key가 없으면 default값 반환.딕셔너리에서 key/value 접근법
max(nums.values())max(nums, key=nums.get)from collections import Counter
nums = [int(input()) for _ in range(10)]
print(sum(nums) // len(nums)) # 평균
cnt = Counter(nums)
print(cnt.most_common(1)[0][0]) # 최빈값
Counter(nums) → 각 숫자의 빈도수를 자동으로 계산Counter({30: 4, 40: 3, 10: 2, 60: 1})cnt.most_common(1) → 가장 자주 나온 값 1개 반환[(30, 4)]cnt.most_common(1)[0][0] → (30, 4) 중에서 30만 추출| 방식 | 코드 길이 | 가독성 | 원리 |
|---|---|---|---|
| dictionary | 길지만 원리 이해에 도움 | ★★★★☆ | .get()으로 직접 count |
| Counter | 짧고 직관적 | ★★★★★ | 자동 카운트 및 most_common() 제공 |
https://www.acmicpc.net/problem/3460
T = int(input())
for _ in range(T):
n = int(input())
bin_n = str(bin(n)[2:])
bin_n = bin_n[::-1]
indices = [i for i,x in enumerate(bin_n) if x == "1"]
print(" ".join(str(i) for i in indices))
| 변환 | 방법 | 예시 | 설명 |
|---|---|---|---|
| 10진수 → 2진수 | bin(n)[2:] | bin(13) → '0b1101' → '1101' | 앞의 '0b'는 접두사이므로 잘라냄 |
| 10진수 → 8진수 | oct(n)[2:] | oct(13) → '0o15' → '15' | '0o' 접두사 제거 |
| 10진수 → 16진수 | hex(n)[2:] | hex(13) → '0xd' → 'd' | '0x' 접두사 제거 |
| n진수 → 10진수 | int(string, base) | int('1101', 2) → 13 | 문자열을 주고 진법을 지정 |
| 직접 정의한 n진수 변환 | 재귀나 반복문으로 구현 가능 | 6진수, 12진수 등 | 기본 내장 함수에는 없음 |
💡
chr(n)은 숫자를 문자 코드(ASCII) 로 바꾸는 함수이므로
진법 변환용이 아니라 문자 변환용이다.
예:chr(65)→'A',ord('A')→65
.join()의 원리문법: "구분자".join(iterable)
조건
iterable은 반복 가능한 객체(list, tuple 등)| 예시 | 결과 | 설명 |
|---|---|---|
" ".join(['1', '2', '3']) | '1 2 3' | 정상 |
"".join(['a', 'b', 'c']) | 'abc' | 구분자 없음 |
" ".join([1, 2, 3]) | ❌ TypeError | 원소가 int |
" ".join(str(i) for i in [1,2,3]) | '1 2 3' | 문자열로 변환 후 정상 |
진법 변환 핵심
bin(), oct(), hex() → 문자열 접두사 제거int(string, base)chr()는 진법 변환이 아니라 문자 코드 변환 함수.join() 핵심
map(str, iterable) 또는 컴프리헨션으로 문자열화 필요.def to_base(n:int, base:int) -> str:
if not (2 <= base <= 36):
raise ValueError("base 는 2~36이하만 지원")
if n == 0:
return "0"
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" # 최대 36진수까지 지원
result = []
is_negative = n < 0
n = abs(n)
while n > 0:
remainder = n % base
result.append(digits[remainder])
n //= base
if is_negative:
result.append("-") #음수용
return ''.join(reversed(result))
-> 몫은 밑으로 나머지는 digits으로 처리해서 result 에 더하고 마지막에 reversed()로 처리.
https://www.acmicpc.net/problem/2745
N,B = input().split()
B = int(B)
print(int(N,B))
파이썬은 내장함수가 있기 때문에 자동으로 해준다!
즉,to_base()는 10진수 → B진수 변환용
int(N, B)는 B진수 → 10진수 변환용
하지만custom으로 짜보면?
N, B = input().split()
B = int(B)
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result = 0
for i, ch in enumerate(reversed(N)): # 뒤에서부터 자리수 계산
value = digits.index(ch) # 해당 문자의 숫자값
result += value * (B ** i)
print(result)
https://www.acmicpc.net/problem/1292
A,B = map(int,input().split())
seq = []
for i in range(1,1001):
seq += [i] * i
print(sum(seq[A-1:B]))
문제:
1을 한 번, 2를 두 번, 3을 세 번, … 이런 식으로 수열 1, 2, 2, 3, 3, 3, …을 만들어
A번째부터 B번째까지의 합을 구하는 문제.
초기 시도:
ans = []
for i in range(1, 10):
ans.append([i] * i)
이렇게 하면 ans = [[1], [2,2], [3,3,3], …] 처럼 리스트 안에 리스트가 생긴다.
이유는 append()가 리스트 전체를 하나의 요소로 추가하기 때문이다.
해결 방법:
+= 연산을 사용하면, 리스트 안에 리스트가 아니라 리스트를 펼쳐서 붙이기(extend) 가 된다.
seq = []
for i in range(1, 10):
seq += [i] * i
이렇게 하면
seq = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4, …]
처럼 원하는 형태의 수열이 만들어진다.
최종 코드:
A, B = map(int, input().split())
seq = []
for i in range(1, 1001):
seq += [i] * i
print(sum(seq[A-1:B]))
핵심 포인트:
append() → 리스트를 요소로 추가 (중첩 구조 생성)+= 또는 extend() → 리스트를 병합(펼쳐서 추가)이 차이만 정확히 이해하면 유사한 문제에서도 헷갈리지 않는다.
https://www.acmicpc.net/problem/1037
n = int(input())
real = list(map(int,input().split()))
print(max(real) * min(real))
배운점
약수의 성질을 살펴보자.24를 예로 들면 (2,12),(3,8),(4,6)으로 조합된다
조합된거에서 각 곱하면 된다
즉, = x 하면 된다.
https://www.acmicpc.net/problem/11047
N,K = map(int, input().split())
coins = [int(input()) for _ in range(N)]
count = 0
for coin in reversed(coins):
if K >= coin:
count += K //coin
K %= coin
print(count)
배운점
탐욕법(Greedy)의 핵심 사고방식
→ "가장 큰 단위부터 가능한 한 많이 써라."
동전이 항상 “작은 단위의 배수 관계”라면,
이 방법이 항상 최적해를 보장한다.
reversed(coins)의 의미
입력은 오름차순(1, 5, 10, 50, …)으로 들어오므로
→ reversed()로 뒤집어 큰 단위부터 순회한다.
if K >= coin: 조건의 역할
너무 큰 단위는 자연스럽게 무시된다.
즉, 4790원일 때 5000원 동전은 패스하고,
1000원 단위부터 계산이 시작된다.
K // coin과 K %= coin의 관계
K // coin: 지금 동전을 몇 개 쓸 수 있는가K %= coin: 그만큼 사용 후 남은 금액결국 작은 동전까지 갈 필요가 없다
위의 과정이 “큰 단위에서 충분히 나눠지면 끝나기 때문”.
이게 바로 탐욕법이 잘 작동하는 이유다.
"큰 단위부터 순서대로, 가능한 만큼 쓰고 남은 금액만 다음 단위에 넘긴다."
https://www.acmicpc.net/problem/2309
from itertools import combinations
dwarfs = [int(input()) for _ in range(9)]
combs = combinations(dwarfs,7)
for comb in combs:
if sum(comb) == 100:
for i in sorted(comb):
print(i)
break
배운점
itertools.combinations() 출력 확인
combinations()는 iterator(이터레이터) 형태라서,
print(combs) 하면 주소처럼 object at 0x... 만 나옵니다.
내부 내용을 보려면 list()로 감싸야 실제 조합을 확인할 수 있습니다.
예:
print(list(combinations([1,2,3], 2)))
# [(1, 2), (1, 3), (2, 3)]
정답 조합을 찾으면 즉시 종료 (break)
break로 루프를 종료해야 합니다.출력은 오름차순 정렬 필요
sorted(comb)를 통해 순서를 맞춰 출력해야 합니다.combinations는 조합이 메모리에 한꺼번에 만들어지지 않고list()는 디버깅할 때만 쓰는 게 좋습니다.)C(9,7) = 36요약하자면,
“조합은
list()로 확인하고, 정답은 찾자마자 멈추자.”
이 두 개가 핵심 포인트입니다.
https://www.acmicpc.net/problem/3058
T = int(input())
for _ in range(T):
ans = []
nums = list(map(int, input().split()))
for num in nums:
if num % 2 ==0:
ans.append(num)
print(f"{sum(ans)} {min(ans)}")
배운점
입력 형태를 먼저 확인해야 한다.
"1 2 3 4 5 6 7" 처럼 공백으로 구분되어 들어온다면,list(map(int, input().split())) 로 한 번에 읽어야 한다.[int(input()) for _ in range(7)] 으로 읽는다.이 문제는 한 줄에 여러 숫자가 입력되는 케이스이므로
nums = list(map(int, input().split())) 가 맞는 방법이다.
ans 리스트에는 짝수만 필터링해서 저장하고,
sum(ans)와 min(ans)를 각각 출력하면 된다.
입력이 공백으로 구분된 한 줄이라면
input().split()으로 처리해야 하며,
이 문제는 그 형태이므로list(map(int, input().split()))가 올바른 입력 방식이다.
https://www.acmicpc.net/problem/16170
from datetime import datetime, timezone, timedelta
uk = datetime.now(timezone(timedelta(hours = 0)))
print(uk.year, uk.month,uk.day)
배운점
(1) 현재시간을 나타날때는 위 from datetime import datetime, timezone, timedelta를 기억하자
그리고 쓰는 방법 또한
datetime.now(timezone(timedelta(hours=0)))으로 기억하도록 하자.
그러면 이러한 문제는 개꿀~
https://www.acmicpc.net/problem/11721
s = input().strip()
for i in range(0,len(s),10):
print(s[i:i+10])
range(0, len(s), 10) 구문을 사용하면 인덱스 계산을 직접 하지 않아도 된다.quotient, remainder = divmod(len(s), 10)처럼 나눗셈으로 범위를 계산하려고 했는데, 이런 복잡한 계산은 필요 없었다.s[i:i+10])은 끝 인덱스가 문자열 길이를 넘어가더라도 오류 없이 잘려서 반환되므로 안전하다.요약:
“문제를 복잡하게 만들지 말자. 단순한 구조가 가장 강력하다.”
https://www.acmicpc.net/problem/1676
def factorial(n:int) -> int:
ans = 1
if n == 0:
return 1
for i in range(1,n+1):
ans *= i
return ans
import sys
input = sys.stdin.readline
N = int(input())
_N = str(factorial(N))
count = 0
for i in reversed(_N):
if i == "0":
count += 1
else:
break
print(count)
배운점
(1) 팩토리얼을 너무 간단하게 정의했다. O(N)의 시간복잡도를 가진다. 뭐 dp로 풀어도 같겠지만.
# dp 로 풀었을때
def factorial(n:int) -> int:
df = [1] * (n+1)
for i in range(1 ,n+1):
dp[i] = dp[i-1] * i
return dp[n]
뭔가 좀더 있어 보인다.
(2) 이렇게 하는것보다 좀 더 효율적인 방식이 있다고 한다. from gpt
import sys
input = sys.stdin.readline
N = int(input())
count = 0
while N >= 5:
count += N // 5
N //= 5
print(count)
이 코드는 “N! (팩토리얼)의 끝자리 0 개수를 효율적으로 세는 방법”입니다.
하나씩 천천히 풀어볼게요.
0은 2 × 5로 만들어집니다.
예를 들어:
10! = 1×2×3×4×5×6×7×8×9×10
여기서 2는 여러 번 등장하지만, 5는 상대적으로 적습니다.
따라서 0의 개수는 5가 몇 번 등장하느냐에 달려 있습니다.
즉,
끝자리 0의 개수 = 1부터 N까지 수에 포함된 5의 개수
1부터 10까지 곱할 때, 5의 배수는 다음과 같습니다:
5, 10
각각 5를 한 번씩 포함하죠.
→ 총 2번 등장 → 끝자리 0은 2개.
5, 10, 15, 20, 25
이 중 25는 5×5, 즉 5를 두 번 포함합니다.
따라서 단순히 “5의 배수 개수”만 세면 안 되고,
“5가 몇 번 곱해졌는지”까지 고려해야 합니다.
그래서 한 번 5로 나누는 것으로는 부족합니다.
while N >= 5:
count += N // 5
N //= 5
| 단계 | N 값 | N // 5 의미 | 누적 count | 설명 |
|---|---|---|---|---|
| 1 | 100 | 20 | 20 | 5의 배수 개수 (5, 10, …, 100) |
| 2 | 20 | 4 | 24 | 25, 50, 75, 100에 있는 추가 5 |
| 3 | 4 | 0 | 24 | 5보다 작으므로 종료 |
👉 결과적으로 24개의 5가 존재, 즉 0이 24개.
N // 5 → 5의 배수에서 생기는 5의 개수N //= 5 → 다음 루프에서 25, 125 등 “5가 여러 번 곱해진 수”까지 카운트count = N!의 끝자리 0 개수| N | 실제 N! 끝의 0 개수 | 계산 결과 |
|---|---|---|
| 5 | 1 | 1 |
| 10 | 2 | 2 |
| 25 | 6 | 6 |
| 100 | 24 | 24 |
뭐 그렇다고 한다 .. 신기하네??
이렇게 푸는 사람이있을려나?? 나는 접근조차도 못하겠는데
https://www.acmicpc.net/problem/11655
def ROT13(s:str) -> str:
result = []
for ch in s:
if "A" <= ch <= "Z":
result.append(chr((ord(ch) - ord("A") + 13) % 26 + ord("A")))
elif "a" <= ch <= "z":
result.append(chr((ord(ch) - ord("a") + 13) % 26 + ord("a")))
else:
result.append(ch)
return "".join(result)
import sys
input = sys.stdin.readline
s = input().rstrip()
print(ROT13(s))
배운점
ord()와 chr()의 개념 이해
ord() → 문자(character)를 유니코드(정수) 로 변환. (“ordinal” = 순서 번호)chr() → 정수(유니코드)를 문자(character) 로 변환.chr(ord('A')) == 'A' 형태로 서로 역함수 관계를 가진다.문자 범위를 문자열로 비교할 수 있음
'A' <= ch <= 'Z''a' <= ch <= 'z'ROT13 변환 과정의 논리적 구조
(1) ord(ch) - ord('A') → ‘A’를 기준으로 정규화 (0~25)(2) +13 → ROT13 규칙에 따라 13칸 회전 이동(3) %26 → A~Z 범위에서 순환 회전(4) +ord('A') → 다시 문자 코드로 복원(복호화)"정규화 → 이동 → 순환 → 복호화" 흐름으로 구성됨.출력 형식 오류 해결
input().rstrip()을 사용하여 입력 문자열 끝의 개행 문자(\n) 를 제거.이 문제를 통해
ord, chr)%)rstrip)등의 개념을 실습하며 문자열 암호화 로직의 기본 구조를 체계적으로 이해할 수 있었다.
추가로 다른 사람의 코드가 있는데 이것 또한 간단해서 좋았다.
import sys
for x in sys.stdin.readline().rstrip():
if x.isalpha():
c = 97 if x.islower() else 65
print(chr(c + (ord(x) + 13 - c) % 26), end='')
else: print(x, end='')
https://www.acmicpc.net/problem/5218
T = int(input())
import sys
input = sys.stdin.readline
for _ in range(T):
s1 ,s2 = map(str, input().split())
distances = []
for i in range(len(s1)):
diff = ord(s2[i])- ord(s1[i])
if diff < 0:
diff += 26
distances.append(diff)
print("Distances:", *distances)
배운점
리스트 초기화 위치
distances를 for i in range(len(s1)): 안에 두면 매 반복마다 초기화되어 값이 누적되지 않는다.문자 거리 계산 순서
ord(s2[i]) - ord(s1[i])+26을 더한다.출력 형식
print("Distances:", *distances)*를 사용하면 리스트의 각 요소를 공백으로 구분해 출력할 수 있다.[1, 3, 5] → 1 3 5ord() : 문자를 아스키코드(숫자)로 변환chr() : 숫자를 문자로 변환+26 보정*list)을 활용하면 출력이 간결해짐https://www.acmicpc.net/problem/11365
while True:
_ls = list(input().split())
ans = []
if _ls[0] == "END":
break
for i in reversed(_ls):
ans.append(i[::-1])
print(" ".join(str(i) for i in ans))
배운점
(1) _ls =="END" 하면 무조건 False가 나옴 왜냐하면 _ls는 기존에 리스트로 정의했으니까.
따라서 _ls[0] 이라고 해줘야함. 이거는 사소하지만 나중에 안됨 ㅋㅋ
(2) 더 깔끔하게 쓰는 방법도 있음
while True:
line = input()
if line == "END":
break
print(" ".join(word[::-1] for word in line.split()[::-1]))
위 방법은 한줄로 print(" ".join(word[::-1] for word in line.split()[::-1])) 로 고쳤음.
https://www.acmicpc.net/problem/10820
import sys
for line in sys.stdin:
line = line.strip("\n")
low = upp = nums = space = 0
for c in line:
if c.islower():
low += 1
elif c.isupper():
upp += 1
elif c.isnumeric():
nums += 1
else:
space += 1
print(low,upp,nums,space)
sys.stdin 활용while문으로 처리하기 어렵기 때문에 for line in sys.stdin: 형태로 EOF까지 자동 읽기.line.strip("\n") 사용.✅ 핵심 원리
sys.stdin은 파일처럼 동작하며,
입력이 끝날 때까지(EOF) 한 줄씩 자동으로 반복된다.
is 계열 메서드의 활용문자열 판별 메서드는 코딩테스트에서 자주 쓰인다.
아래는 대표적인 것들이다.
| 메서드 | 참(True) 조건 | 예시 |
|---|---|---|
| isalpha() | 모든 문자가 알파벳(a–z, A–Z) 일 때 | "abc".isalpha() → ✅ True"abc1".isalpha() → ❌ False |
| isdigit() | 모든 문자가 0–9 숫자일 때 | "123".isdigit()" → ✅"12a".isdigit() → ❌ |
| isnumeric() | 모든 문자가 숫자(0–9 + 유니코드 숫자 포함, 예: Ⅻ)일 때 | "Ⅻ".isnumeric() → ✅ |
| isalnum() | 모든 문자가 알파벳 또는 숫자일 때 | "abc123".isalnum() → ✅ |
| islower() | 모든 문자가 소문자일 때 (한 글자 이상) | "abc".islower()" → ✅"Abc".islower()" → ❌ |
| isupper() | 모든 문자가 대문자일 때 | "ABC".isupper()" → ✅"ABc".isupper()" → ❌ |
| isspace() | 모든 문자가 공백 문자(스페이스, 탭, 줄바꿈 등) 일 때 | " ".isspace()" → ✅ |
| istitle() | 문자열이 Title Case (단어 첫 글자만 대문자)일 때 | "Hello World".istitle()" → ✅"Hello world".istitle()" → ❌ |
| isprintable() | 모든 문자가 출력 가능한 문자(제어문자 제외) 일 때 | "abc!".isprintable()" → ✅ |
| isascii() | 모든 문자가 ASCII(0~127) 범위일 때 | "abc".isascii()" → ✅"한글".isascii()" → ❌ |
isdigit()과 isnumeric()은 비슷하지만, 후자는 로마 숫자, 분수, 동아시아 숫자 등 유니코드 숫자도 True로 인식.isalpha()는 오직 알파벳만 허용하며, 공백이나 숫자가 섞이면 False.https://www.acmicpc.net/problem/10951
이 문제도 똑같이 EOF가 없는 상황
import sys
for line in sys.stdin:
line = line.strip("\n")
A,B = line.split()
print(int(A)+int(B))