문제

 

1193번: 분수찾기

첫째 줄에 X(1 ≤ X ≤ 10,000,000)가 주어진다.

www.acmicpc.net

출처: 백준 1193번 문제

이런 표가 있고 움직이는 패턴이 있을 때, 몇번째 분수가 뭔지 찾는 것. 패턴은 풀이란에 넣어드림. 참고로 오늘 쓰는 건 근의 공식밖에 없으므로 따로 설명을 넣거나 하지는 않습니다.

 

풀이

움직이는 패턴이 이런 식이다. 보자마자 마른세수 마렵다면 지극히 정상이다. 나도 그랬음. 이건 수능에 실렸으면 저기 어디 중간 페이지에는 나왔을 문제다. 공명의 함정은 아니지만 일단 당황하지 말고, 저기에 있는 패턴을 파악해보자.

1번째 줄: 1/1

2번째 줄: 1/2, 2/1

3번째 줄: 3/1, 2/2, 1/3

4번째 줄: 1/4, 2/3, 3/2, 4/1

5번째 줄: 5/1, 4/2, 3/3, 2/4, 1/5

봐도 모르겠다고? 일단 여기서 패턴은 크게 두 개인데

  1. 분자와 분모의 패턴
  2. 줄간 패턴

이렇게 있다. 그럼 굵직한 패턴부터 보고 가자.

 

줄간 패턴

줄간 패턴은 크게 두 개인데, 전체적으로 줄의 번호 수(n)만큼 분수를 가지고 있으며 각 줄의 시발점(욕 아님)과 종점의 분자 혹은 분모가 해당 줄 번호이다. 세번째 줄을 보면 분수가 총 3개이고, 시발점의 분자와 종점의 분모가 3이다. 그리고 줄의 누적합은 순서대로 1, 3, 6, 10, 15, … 이다. 이건 초항이 1, 공차가 1인 등차수열의 각각 1, 2, 3, 4, 5번째까지의 합이고, 줄에 있는 분수의 수도 실제로 초항이 1, 공차가 1인 등차수열.

분수의 패턴

이거는 홀수번째 줄과 짝수번째 줄의 패턴이 반대인데, 세번째 줄은 분자가 큰 수에서 하나씩 감소하고 분모가 작은 수에서 큰 수로 하나씩 증가한다. (분자가 3, 2, 1이고 분모가 1, 2, 3) 짝수번째 줄은 반대로 분자가 작은 수에서 하나씩 증가하고 분모가 큰 수에서 하나씩 감소한다.

등차수열

솔직히 여기까지 봐도 근의 공식이 뭔 상관인지 모르겠지들? 그럼 뜬금포로 왜!!! 근의공식!!! 2에이분의 마이나쓰 비 플마 루트 비제곱 마이나쓰 4에이씨가 나왔는지 설명을 할 건데… 줄간 패턴에서 각 줄의 분수 숫자가 초항이 1이고 공차가 1인 등차수열이고 분수의 총 개수가 해당 등차수열의 합계라고 했다. 아니 스크롤도 안 넘겼어 그걸 까먹으면 어떡함… 아무튼, 등차수열의 일반항… 그러니까 이 문제에서 n번째 줄의 분수 개수(an)를 구하는 공식은

이거다. 여기서 a_1=1, d=1을 대입하고 풀면 a_n=n이 된다. 즉, n번째 줄의 분수 개수는 n개이다. 그리고 초항이 a_1, 공차가 d인 등차수열의 a_n항까지의 합은

이거다. 여기다가도 마찬가지로 a_1=1, d=1을 대입해보면 최종적으로

이 식을 도출할 수 있다. 즉, 저 식이 =0일때를 상정하고 근의 공식에 넣는거고, 우리가 입력하는 숫자 N은 앞의 문제와 마찬가지로 ‘또’ =0에서 0을 빼고 거기에 들어갈 거라 이항정리가 필요한데…

예시로 딱 나눠 떨어지는 10을 가져왔다. 그럼 여기서 어떻게 푸느냐… 2차, 1차 항의 계수를 1/2로 놓고 풀던가(이 경우 상수항은 그냥 넘어가면 장땡이라 편함), 양변에 2를 곱해 분모를 치워버리던가(2차, 1차 항의 계수가 1이 되고 상수항에 곱하기 2를 한다). 본인은 후자요.

import sys
import math
a = int(sys.stdin.readline())
c = a * -2
# 이제 이거 없으면... 섭하죠? 
line=int(-(-(-1 + math.sqrt((1 * 1) - 4 * 1 * c)) // 2))
print(line)

줄 수는 이런 식으로 도출하면 된다. 저기서 합계가 아닌 숫자, 그러니까 11, 12, 18 이런 숫자들은 소수점에 뭐가 붙는데, 그걸 일단 떼버리면 줄 번호가 된다. 11, 12는 10보다 크니까 5번째 줄에 있을거고 18은 5보다 크니까 6번째 줄에 있다.

import sys
import math
a = int(sys.stdin.readline())
c = a * -2
# 이제 이거 없으면... 섭하죠? 
line = int(-(-(-1 + math.sqrt((1 * 1) - 4 * 1 * c)) // 2))
# 몇 번째 줄?
maxline = sum(list(range(1,line+1)))
minline = sum(list(range(1,line)))+1
# 그 줄의 최댓값과 최솟값
gap = a - minline
# 줄의 최댓값과 내가 가진 값의 차이는? 
if line % 2 == 0:
    bunja = gap + 1
    bunmo = line - gap
else: 
    bunja = line - gap
    bunmo = gap + 1
print('{0}/{1}'.format(bunja,bunmo))

일단 변수의 의미부터 보고 갑시다.

 

Maxline: 그 줄의 최댓값(초항이 1이고 공차가 1인 등차수열의 n번째 줄까지의 합)

minline: 그 줄의 최솟값(초항이 1이고 공차가 1인 등차수열의 n-1번째 줄까지의 합+1)

 

예를 들어서 5번째 줄이면 Maxline은 1+2+3+4+5 해서 15, minline은 (1+2+3+4)+1 해서 11이다. 이걸로 그 줄의 최댓값과 최솟값을 찾게 되는 것. 아직까지는 줄을 찾은거고, 이제 실질적으로 이게 몇번째인지를 찾아야 하는데 그 역할을 하는 변수가 gap이다. 예를 들어서 13번째 분수를 찾는다고 하면, 13은 11보다 2 크기 때문에 5번째 줄의 최솟값(11)에서 두 개 떨어진다.

 

로직 부분은 간단하다. 짝수줄의 경우 분자가 증가, 분모가 감소이고 홀수줄은 짝수랑 반대. 예를 들어서 12를 입력했다, 그러면 gap이 1이 되는데

 

1. line(줄 번호)은 5이므로 2로 나누었을 때 나머지가 1이다.

2. 분자는 5-1을 해 주고, 분모는 1+1을 해 준다. (gap에 하나 안 더하면 각 줄의 첫번째는 분모나 분자가 0이 된다)

3. 따라서 4/2가 나온다.

 

이렇게 된다. …솔직히 나도 이거 한번에 맞을 줄 몰랐음…ㅋㅋㅋㅋ

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 10250번 풀이  (0) 2022.08.18
백준 2869번 풀이  (0) 2022.08.18
백준 2292번 풀이  (0) 2022.08.18
백준 1712번 풀이  (0) 2022.08.18
백준 2941번 풀이  (0) 2022.08.18

문제

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

 

2292번: 벌집

위의 그림과 같이 육각형으로 이루어진 벌집이 있다. 그림에서 보는 바와 같이 중앙의 방 1부터 시작해서 이웃하는 방에 돌아가면서 1씩 증가하는 번호를 주소로 매길 수 있다. 숫자 N이 주어졌

www.acmicpc.net

이 문제는 한줄요약이 안된다… 대충 1번 방에서 n번째 방까지 가는 최단거리를 구하는 문제. 참고로 벌집의 방 수에는 패턴이 있다. 

 

Reference

https://swkang.tistory.com/m/7

 

[BOJ]2292번 벌집(Python)

https://www.acmicpc.net/problem/2292 2292번: 벌집 위의 그림과 같이 육각형으로 이루어진 벌집이 있다. 그림에서 보는 바와 같이 중앙의 방 1부터 시작해서 이웃하는 방에 돌아가면서 1씩 증가하는 번호를

swkang.tistory.com

 

계차수열과 근의 공식

왜 이게 나오냐면 내가 이걸로 풀어서요.

 

계차는 수열의 항과 항 사이의 차이다. 정확히는 뒤의 항에서 앞의 항을 뺀 것이 계차이고, 그 계차들로 이루어진 수열이 계차수열. 즉, 계차수열은 수열이 있어야 성립한다. 개 아니고 계다

계차수열의 일반식은 이걸로 구하고,

계차수열을 이용해 원래 수열의 일반항을 구할 때는 이걸로 구한다.

 

근의 공식은 이차방정식 ax^2+bx+c=0이 있을 때

이걸로 정의한다. 일단 그래서 또 가져올 코드가 있어요…

import math;
print('2차방정식의 근의 공식은 다음과 같습니다: \n'
      'a, b, c가 실수이며 a<>0일때 이차방정식 ax^2 + bx + c의 해를 구하는 공식 '
      '-b +- 루트(b^2 - 4ac) / 2a');
print('또한 이차방정식의 판별식인 b^2 - 4ac를 이용해 근이 중근인지, 서로 다른 실근인지, 허근인지도 알 수 있습니다. ');
a=int(input('이차항 계수를 입력해주세요 '));
b=int(input('일차항 계수를 입력해주세요 '));
c=int(input('상수항 계수를 입력해주세요 '));
d=(b*b)-(4*a*c);

if d>0:
    print('이 방정식은 서로 다른 두 실근을 가집니다. ');
    e = round((-b + math.sqrt((b * b) - 4 * a * c)) / (2 * a),3);
    f = round((-b - math.sqrt((b*b)-4*a*c))/(2*a),3);
    print(e);
    print(f);
elif d==0:
    print('이 방정식은 중근을 갖습니다. ');
    e = round((-b + math.sqrt((b * b) - 4 * a * c)) / (2 * a),3);
    print(e);
else:
    print('이 방정식은 허근을 갖습니다. ');
    e = (-b / (2 * a));
    f = round(math.sqrt(abs(b * b - 4 * a * c)) / 2 * a,3);
    print(str(e)+'+-'+str(f)+'i');

예전에 이차식의 계수를 입력하면 근의 공식에 대입해서 근을 구해주고, 판별식을 통해 이 방정식의 근이

  1. 서로 다른 두 실근(>0)
  2. 중근(=0)
  3. 허근(<0)

인지도 계산해주는 코드를 짰었는데, 오늘은 이 코드에서 ‘서로 다른 두 실근일 때 양의 실근’을 구하는 공식을 가져올 예정이다.

 

풀이

일단 코딩에 앞서 일반화를 해야 한다. (마른세수)

출처ㅣ 백준 2292번 문제

이게 그 벌집이다. 보면 되게 중구난방인 것 같지만… 일단 진정하고 아래 그림을 보자.

일단 저기서 1 말고(얘는 방이 하나임) 그 바깥줄부터 보자. …아니 시발점은 보지 말고 종점만 봅시다. 그러면 순서대로 7, 19, 37, 61이다. 아니 이게 무슨 패턴이 있어욧!! 아니 분명 있다니깐여 내가 아까 계차수열 말할 때 뭐 들었음? 계차수열이랑 이게 뭔 상관인지 모르겠다고? 자 그럼 가운데 방부터 시작해서 하나하나 짚어보자. 일단 방의 종점에 대한 수열을 a라고 하면

a1=1

a2=7

a3=19

a4=37

a5=61

이렇게 된다.

a1=1

a2=a1+6

a3=a2+12

a4=a3+18

a5=a4+24

이렇게 6배수 차이가 난다. 즉, 이 수열은 아무 패턴이 없어보이게 훼이크를 줬지만 계차수열의 초항이 6, 공차가 6인 ‘등차수열’을 이루고 있다.

계차수열의 패턴과 일반화 공식을 이용하면 3n^2-3n+1이라는 식이 도출되게 된다. 그럼 이 다음은? 근의 공식에 대입하면 된다.

씁 뭔가 쎄한데…? 이건 3n^2-3n+1=0일 때의 값이다. 실제로 계산해보면

2차방정식의 근의 공식은 다음과 같습니다: 
a, b, c가 실수이며 a<>0일때 이차방정식 ax^2 + bx + c의 해를 구하는 공식 -b +- 루트(b^2 - 4ac) / 2a
또한 이차방정식의 판별식인 b^2 - 4ac를 이용해 근이 중근인지, 서로 다른 실근인지, 허근인지도 알 수 있습니다. 
이차항 계수를 입력해주세요 3
일차항 계수를 입력해주세요 -3
상수항 계수를 입력해주세요 1
이 방정식은 허근을 갖습니다. 
0.5+-2.598i

이차식의 계수를 그대로 입력하면 허근이 나오는 게 맞다.

2차방정식의 근의 공식은 다음과 같습니다: 
a, b, c가 실수이며 a<>0일때 이차방정식 ax^2 + bx + c의 해를 구하는 공식 -b +- 루트(b^2 - 4ac) / 2a
또한 이차방정식의 판별식인 b^2 - 4ac를 이용해 근이 중근인지, 서로 다른 실근인지, 허근인지도 알 수 있습니다. 
이차항 계수를 입력해주세요 3
일차항 계수를 입력해주세요 -3
상수항 계수를 입력해주세요 -12
이 방정식은 서로 다른 두 실근을 가집니다. 
2.562
-1.562

0이 들어갈 자리에 13을 넣고 이항정리를 하면 이렇게 나온다. (반올림하면 3 맞음) 그럼 이제 IDE를 켜보자.

import sys
a=int(sys.stdin.readline())
# 역시나 유서깊은(?) sys.stdin.readline()입니다. 
# 뭐요.

입력은 역시나 유서깊은 sys.stdin.readline()으로 해 준다.

(-b + math.sqrt((b*b)-4*a*c))/(2*a)

근의 공식 코드에 쓰였던 건 얜데, math가 모듈이다. 그래서 저걸 불러와야 쓸 수 있다. …사실 백준에서 sys말고 뭐 불러본 적이 없음… 아무튼 그럼 제곱근 못써요?

a ** 0.5

걍 지수승에 분수 주면 된다. 일반적으로 루트 끼고 들어가는 제곱근은 1/2승으로 주면 된다.

import sys
a=int(sys.stdin.readline())
# 역시나 유서깊은(?) sys.stdin.readline()입니다. 
# 뭐요. 
c = 1 - a
n = (-(-3) + ((9-12*c) ** 0.5))/6
print(int(n)+1)

그리고 이렇게 한 다음 와 됐다 하고 냈더니 틀렸대. 알고보니 1 넣으면 1이 나와야 하는데 2가 나오는 것이었다

import sys
a=int(sys.stdin.readline())
# 역시나 유서깊은(?) sys.stdin.readline()입니다. 
# 뭐요. 
c = 1 - a
n = -(-(3 + ((9-12*c) ** 0.5))//6)
print(int(n))

일단 연산자를 //로 바꾸고(//는 몫만 나온다. 6//5=1), 저게 음수를 나눌 때는 숫자가 올림이 되기 때문에 참고문헌에서는 음수로 바꾼 다음 나누고 양수로 바꾸셨다. (그리고 형변환은 덤)

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 2869번 풀이  (0) 2022.08.18
백준 1193번 풀이  (0) 2022.08.18
백준 1712번 풀이  (0) 2022.08.18
백준 2941번 풀이  (0) 2022.08.18
백준 5622번 풀이  (0) 2022.08.18

문제

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

 

1712번: 손익분기점

월드전자는 노트북을 제조하고 판매하는 회사이다. 노트북 판매 대수에 상관없이 매년 임대료, 재산세, 보험료, 급여 등 A만원의 고정 비용이 들며, 한 대의 노트북을 생산하는 데에는 재료비와

www.acmicpc.net

손익분기점을 구하는 문제. 참고로 부등식이다.

 

방정식과 부등식

방정식은 식에 등호(=)가 있고, 부등식은 식에 부등호(<,>)가 있다. (대충 펀쿨섹좌 짤)

 

그래서 x+y=1은 방정식이고, x+y>1은 부등식이다. 여기서 왜 부등식을 쓰느냐… 손익분기점은 비용보다 커야 하기 때문. 어디서 많이 본 것 같다고? 저거 중학생때 배우는겁니다 여러분.

 

일반화

그럼 이제 일반화를 해 보도록 하자.

 

고정비용 A, 가변비용 B가 있고 가변비용은 생산량에 따라 비용이 배가된다. 즉 물건을 하나 생산할 때는 A+B, 두 개 생산할 때는 A+2B 이런 식이 된다. 그리고 C는 물건의 판매가. 그래서 일반화한 식이 A + Bx < Cx가 된다. 그리고 이항정리를 하게 되면 A < Cx – Bx를 거쳐서 A < (C – B)x가 된다.

 

그리고 이 식을 다시 x에 맞게 정리하게 되면 최종적으로 A / (C – B) < x가 된다.

 

풀이

일단 Python에서도 모듈을 깔면 방정식을 풀 수 있다. 바로 sympy와 mpmath.

import sys
from sympy import *
from mpmath import mp
init_printing()
# Sympy
A,B,C=map(int,sys.stdin.readline().split(" "))
x=Symbol('x')
# A, B, C는 입력받는 변수(고정비용, 가변비용, 판매가)
# 이 때 손익분기점에 대한 부등식은 A+Bx<Cx이다. 
expr=A < (C - B) * x
print(solve(expr))

x를 심볼화하고 solve() 던지면

(10 < x) & (x < oo)

이렇게 나온다. 그러면 x가 10보다 커야 하니 제일 가까운 정수는 11. 근데 이걸로 내면 출력 형식때문에 틀려요…

import sys
A,B,C=map(int,sys.stdin.readline().split(" "))
# A, B, C는 입력받는 변수(고정비용, 가변비용, 판매가)
# 이 때 손익분기점에 대한 부등식은 A+Bx<Cx이다. 항을 정리해주게 되면 A < (C - B)x가 된다. 
# 단, sympy를 부를 수 없으므로... 
x = 0
y = C - B
while x * y <= A:
    x += 1
    x * y
print(x)
# 뺑뺑이 돌릴거다.

그럼 어쩌겠음 뺑뺑이 돌려야지. 근데 문제가 하나 있다. 이 코드도 맞는 답을 내놓는 건 맞는데, 이걸로 주면 시간초과 나온다. 그리고 저 코드는 한가지가 빠졌다. 바로 답이 없는 경우에 -1로 처리하는 코드가 없다. 그니까 아싸 끝 하고 저거 갖다 내면 뭐다? 틀린다.

import sys
A,B,C=map(int,sys.stdin.readline().split(" "))
# A, B, C는 입력받는 변수(고정비용, 가변비용, 판매가)
# 이 때 손익분기점에 대한 부등식은 A+Bx<Cx이다. 항을 정리해주게 되면 A < (C - B)x가 된다. 
# 단, sympy를 부를 수 없으므로... 
x = 0
y = C - B
if y < 0:
    print(-1)
else: 
    while x * y <= A:
        x += 1
        x * y
    print(x)
# 뺑뺑이 돌릴거다.

손익분기점이 있는 케이스와 없는 케이스 둘 다 sympy로 만든 코드에 넣었을 때 해가 어떻게 되느냐, 손익분기점이 있는 케이스는 C – B, 즉 판매 비용과 가변 비용의 차가 양수이고 손익분기점이 없는 케이스(3 2 1)는 C – B가 음수, 즉 0보다 작다. 거기에 대한 처리를 한 게 저 코드인데 아직 내지 말아봐… 저거 시간초과여.

import sys
A,B,C=map(int,sys.stdin.readline().split(" "))
# A, B, C는 입력받는 변수(고정비용, 가변비용, 판매가)
# 이 때 손익분기점에 대한 부등식은 A+Bx<Cx이다. 항을 정리해주게 되면 A < (C - B)x가 된다. 
# 단, sympy를 부를 수 없으므로... 
x = 0
if C - B < 0:
    print(-1)
else:  
    x = A / (C - B)
    print(int(x+1))
# 루프문 시간초과 실화냐고

루프를 안 돌리고 다이렉트로 구해버리면 시간초과는 해결이다. 와! 그럼 내도 돼요? 아니 있어봐 저거 내면 Zerodivision 떠… 선생님 되게 행복회로 태웠는데 에러나면 엿같잖아요…

import sys
A,B,C=map(int,sys.stdin.readline().split(" "))
# A, B, C는 입력받는 변수(고정비용, 가변비용, 판매가)
# 이 때 손익분기점에 대한 부등식은 A+Bx<Cx이다. 항을 정리해주게 되면 A < (C - B)x가 된다. 
# 단, sympy를 부를 수 없으므로... 
x = 0
if C - B <= 0:
    print(-1)
else:  
    x = A / (C - B)
    print(int(x+1))
# 루프문 시간초과 실화냐고

Zerodivision은 어떤 수를 0으로 나누려고 하면 생기는 문제이다. n / 0 (n != 0)이면 불능, 0 / 0은 부정이다. 아무튼 그러한 이유로 C – B가 0일때도 -1이 뜨도록 처리해야 한다.

 

Appendix. 부정과 불능

부정은 해가 더럽게 많은거고, 불능은 알파고 할아버지가 와도 답이 없는 케이스. 알파고는 할아버지가 없는데요

 

0으로 나누는 케이스의 경우 0 / 0이 부정인 이유를 이해하려면 나눗셈이 곱셈과 서로 역연산 관계라는 것을 알고 가야 한다. 부정은 해가 개 많은거라고 했는데, 0 / 0 = C라고 하면 0 = C * 0이 되고 여기에 들어갈 수 있는 C가 사실상 정말 겁나 완전 핵 많기 때문에 부정. 불능은 n / 0 = C (단, n != 0)라고 할 때 n = C * 0이고 이를 만족하는 C가 없으므로 불능.

 

계산기에서 0으로 나누면 에러 뜨는 이유도 그것때문이다. 나눗셈이라는 건 피제수에서 제수를 빼고 빼고 빼고 하는거고, 최종적으로 몇 번 뺐느냐가 몫, 얼마 남았느냐가 나머지(몫보다 작은 수)가 되는데 0을 빼게 되면 아주 주구장창 0만 빼야 한다. 사용자가 종료하거나(…) 비스무트 방사성 동위원소 반감기 도래하거나(대략 (1.9±0.2) ×1019년) 우주 멸망하거나 프로그램이 뻗을때까지 해야 한다. 대충 break 조건 없는 while True: 에 갇힌다고 생각하면 된다.그래서 대부분의 프로그램이나 계산기는 0으로 나누려고 하면 에러를 토한다.

 

아, !=는 다르다는 얘기다.

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 1193번 풀이  (0) 2022.08.18
백준 2292번 풀이  (0) 2022.08.18
백준 2941번 풀이  (0) 2022.08.18
백준 5622번 풀이  (0) 2022.08.18
백준 2908번 풀이  (0) 2022.08.18

문제

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

 

2941번: 크로아티아 알파벳

예전에는 운영체제에서 크로아티아 알파벳을 입력할 수가 없었다. 따라서, 다음과 같이 크로아티아 알파벳을 변경해서 입력했다. 크로아티아 알파벳 변경 č c= ć c- dž dz= đ d- lj lj nj nj š s= ž z=

www.acmicpc.net

크로아티아 알파벳을 포함해 몇 글자인지 세기. (그러니까 (c=,c-,dz=,d-,lj,nj,s=,z=)를 포함해서 세는거다)

 

풀이

import sys
a = sys.stdin.readline().strip()
croatian_alphabet=["c=","c-","dz=","d-","lj","nj","s=","z="]
for i in croatian_alphabet:
    if a.find(i) != -1: 
        a=a.replace(i,"*")
print(len(a))

이건 사실 크로아티아 알파벳 만들어놓고 문자열에서 크로아티안 알파벳을 찾았을 때 한 글자짜리로 바꾼 다음(코드에서는 *) 길이 쟀다. 어쨌든 길이 제대로 재 주면 되는 거 아님? 이런 논리왕같으니

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 2292번 풀이  (0) 2022.08.18
백준 1712번 풀이  (0) 2022.08.18
백준 5622번 풀이  (0) 2022.08.18
백준 2908번 풀이  (0) 2022.08.18
백준 1152번 풀이  (0) 2022.08.18

문제

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

 

5622번: 다이얼

첫째 줄에 알파벳 대문자로 이루어진 단어가 주어진다. 단어의 길이는 2보다 크거나 같고, 15보다 작거나 같다.

www.acmicpc.net

다이얼에 맞는 번호로 환산해서 돌리는 데 걸리는 시간 구하기.

이게 문제의 다이얼이다. (출처: 백준 5622번 문제)

 

 

풀이

일일이 if먹여서 해결한 본인에게 치얼스… 야 이걸 푸네

 

여담이지만 옛날 핸드폰들은 터치고 뭐고 자판이 쿼티가 아니라 천지인 다 이런거였고 영문자를 실제로 저렇게 다이얼에 할당해뒀다. Z를 입력하려면 입력모드를 영대(영어 대문자)로 하고 9를 네 번 누르면 된다. 그래서 저 시절 핸드폰은 입력 자판이 지금처럼 언어별이 아니라 한글-영대-영소-특문(이모티콘)-숫자순이었다. 피처폰 시절에는 그래서 일본어로 글 쓰려면 컴퓨터로 들어가야 했고(자판 셋업하고…). 지금은 뭐…

 

내 핸드폰에 한글 영어 일어 독어 임티 자판 있음. 이거면 설명 끝.

 

import sys
a=sys.stdin.readline()
for i in a:
    print(i)

일단 이렇게 하면 각개로 뽑는 건 된다. 뒷 일이 문제지. 그래서 한참을 고민하다 잠깐 화장실을 갔는데 ASCII 써먹자! 가 생각나서 각 다이얼 별로 맨 뒤 알파벳을 뽑아봤다.

  • 1: 없음
  • 2: C
  • 3: F
  • 4: I
  • 5: L
  • 6: O
  • 7: S
  • 8: V
  • 9: Z
  • 0: Operator

이게 그 측간신 버프냐 아무튼 여기서 실질적으로 0과 1은 할당된 알파벳이 없어서 안 쓰기때문에 다이얼은 2~9까지이고, 시간은 1씩 더한 3~10까지이다.

  • 2: 67
  • 3: 70
  • 4: 73
  • 5: 76
  • 6: 79
  • 7: 83
  • 8: 86
  • 9: 90

그리고 각 다이얼을 ASCII 번호로 변환하면 이렇게 된다. 그럼 어떻게 한다? 범위 잡고 if 착수해야지.

import sys
a = sys.stdin.readline().strip()
time = 0
for i in a:
    if ord(i) <= 67: 
        time += 3
    elif ord(i) <= 70:
        time += 4
    elif ord(i) <= 73:
        time += 5
    elif ord(i) <= 76:
        time += 6
    elif ord(i) <= 79: 
        time += 7
    elif ord(i) <= 83:
        time += 8
    elif ord(i) <= 86:
        time += 9
    else: 
        time += 10
print(time)

각 다이얼별로 끝나는 ASCII 번호가 있고, 그 번호보다 작으면 소요시간을 할당하는 식. 입력은 알파벳이고, 실질적으로 ASCII 번호로 변환하기때문에 범위는 어차피 65~90이다.

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 1712번 풀이  (0) 2022.08.18
백준 2941번 풀이  (0) 2022.08.18
백준 2908번 풀이  (0) 2022.08.18
백준 1152번 풀이  (0) 2022.08.18
백준 10809번 풀이  (0) 2022.08.18

문제

 

2908번: 상수

상근이의 동생 상수는 수학을 정말 못한다. 상수는 숫자를 읽는데 문제가 있다. 이렇게 수학을 못하는 상수를 위해서 상근이는 수의 크기를 비교하는 문제를 내주었다. 상근이는 세 자리 수 두

www.acmicpc.net

세자리 수 두 개를 입력하면 그 수를 거꾸로 뒤집은 다음 큰 수를 출력하는 문제. 에헤이 개초보인 나도 풀었는데 님들도 할 수 있음. 판다스에 바이오파이썬까지 굴리면서 무슨 개초보야 텐서플로우 못쓰는데요 아니 그건 걔가 특수한거지

 

풀이

일단 본격적인 풀이에 들어가기 앞서, 한가지 보고 갈 코드가 있다.

a=input("입력해주세요 \n")
a=a.lower() # 영어일 경우 전부 소문자로
a=a.replace(" ","") # 공백이 있을 경우 공백을 붙여버림

if a == a[::-1]:
    print(True)
else:
    print(False)
# 그래서 짜잔 나왔다

이 코드는 어떤 문장이 회문인지를 판별하는 코드이다. 회문이란, 거꾸로 써도 똑같은 문장… 그러니까 기러기, 스위스, 토마토같은 것이다. 여보 안경 안보여도 회문. 사실 이 문제가 쉬웠던 것도 이걸 미리 해 본 덕분. 아무튼, 그래서 여기서 뭘 갖다 쓸거냐…

a[::-1]

이거다. 이게 뭔지는 풀이 들어가면서 알려드림.

import sys
a,b=sys.stdin.readline().strip().split(" ")
print(a,b)

입력은 역시 역사와 전통의 5G-LTE급 sys.stdin.readline()이다. strip()은 sys.stdin.readline()이 특성상 뒤에 공백이 붙는데 그거 떼려고 넣은거고, split()이 본론. 아무튼 이렇게 하면 입력은 되는데요… 그럼 어떻게 뒤집죠?

a[::-1]

이거요. 참고로 회문 판독 코드에서 if문 조건에 들어가 있다는 걸 알면 금방 유추할 수 있다.

import sys
a,b=sys.stdin.readline().strip().split(" ")
a_num=int(a[::-1])
b_num=int(b[::-1])
if a_num > b_num:
    print(a_num)
else: 
    print(b_num)

출력은 그냥 얘랑 쟤랑 애가 크면 얘 아니면 쟤 뽑으면 된다.

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 2941번 풀이  (0) 2022.08.18
백준 5622번 풀이  (0) 2022.08.18
백준 1152번 풀이  (0) 2022.08.18
백준 10809번 풀이  (0) 2022.08.18
백준 11720번 풀이  (0) 2022.08.18

문제

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

 

1152번: 단어의 개수

첫 줄에 영어 대소문자와 공백으로 이루어진 문자열이 주어진다. 이 문자열의 길이는 1,000,000을 넘지 않는다. 단어는 공백 한 개로 구분되며, 공백이 연속해서 나오는 경우는 없다. 또한 문자열

www.acmicpc.net

어떤 문장에서 단어가 몇 개인지를 세는 문제. 즉

전격은 10만볼트에 이르기도 해서 잘못 만지면 인도 코끼리라도 기절한다.

이 문장은 9글자다. 근데 이 문제… 부비트랩 있다…

 

풀이

import sys
a=sys.stdin.readline().strip()
a=a.split(" ")
print(len(a))

마! 그럼 단어와 단어 사이는 문장으로 나누니까 공백으로 나누면 되제! 하고 이래 냈다가 당신을 맞는 문장은 ‘틀렸습니다’가 된다. 문제에 부비트랩이 숨어있기 때문.

첫 줄에 영어 대소문자와 공백으로 이루어진 문자열이 주어진다. 이 문자열의 길이는 1,000,000을 넘지 않는다. 단어는 공백 한 개로 구분되며, 공백이 연속해서 나오는 경우는 없다. 또한 문자열은 공백으로 시작하거나 끝날 수 있다.

입력란에 이렇게 쓰여있다. split(” “)은 공백을 하나만 날리기때문에, 공백으로 입력하게 되면 그걸 단어로 처리해버리는 문제가 있다. 그래서

import sys
a=sys.stdin.readline().strip()
a=a.split()
print(len(a))

그래서 split()을 줘야 한다. split()은 공백이 몇 개건 po분리wer이 가능하기 때문.

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 5622번 풀이  (0) 2022.08.18
백준 2908번 풀이  (0) 2022.08.18
백준 10809번 풀이  (0) 2022.08.18
백준 11720번 풀이  (0) 2022.08.18
백준 1065번 풀이  (0) 2022.08.18

문제

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

 

10809번: 알파벳 찾기

각각의 알파벳에 대해서, a가 처음 등장하는 위치, b가 처음 등장하는 위치, ... z가 처음 등장하는 위치를 공백으로 구분해서 출력한다. 만약, 어떤 알파벳이 단어에 포함되어 있지 않다면 -1을 출

www.acmicpc.net

영어 소문자로 주어지는 단어에서 알파벳을 찾아서 있으면 그 알파벳의 위치를, 없으면 -1을 출력한다.

 

Reference

https://ooyoung.tistory.com/68

 

백준 10809번 [파이썬] 알파벳 찾기 : Python find( ) 함수 활용

[Python] 백준 알고리즘 온라인 저지 10809번 : 알파벳 찾기 Python3 코드 word = input() alphabet = list(range(97,123)) # 아스키코드 숫자 범위 for x in alphabet : print(word.find(chr(x))) Python3 코..

ooyoung.tistory.com

 

풀이

import sys
a=sys.stdin.readline().strip()

일단 역사와 전통의 sys.stdin.readline()을 써 보도록 하자. 뭔 역사와 전통이여

import sys
a=sys.stdin.readline().strip()
b=list("abcdefghijklmnopqrstuvwxyz")
# 이거 한번에 못만드나... 
b_find=[]
for i in range(len(b)):
    if a.find(b[i]):
        print(a.find(b[i]))
    else: 
        print(-1)

근데 이렇게 했더니 첫 글자를 계속 못찾는겨…

 

그래서 다른 분들은 어떻게 했나 찾다가 저기를 발견했는데, ASCII 코드로 푸셨더라니까요.

import sys
a=sys.stdin.readline().strip()
b=list(range(97,123))

일단 번호를 왜 저렇게 하느냐면 ASCII 코드에서 97번이 소문자 a이고 122번이 소문자 z다. 근데 122까지 잡으면 리스트 마지막이 121까지 옵니다. 왜냐… range()는 부터~미만이거든…

import sys
a=sys.stdin.readline()
b=list(range(97,123))
for i in range(len(b)):
    print(a.find(chr(b[i])))

if도 필요 없단다. find()는 원래 값이 없으면 -1을 반환하는 애거든… (index는 없으면 에러뜸)

import sys
a=sys.stdin.readline()
b_u=list(range(65,91))
b_l=list(range(97,123))
b=b_u+b_l
for i in range(len(b)):
    print(a.find(chr(b[i])))

자매품: 이건 대문자도 같이 찾아준다(65가 ASCII A)

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 2908번 풀이  (0) 2022.08.18
백준 1152번 풀이  (0) 2022.08.18
백준 11720번 풀이  (0) 2022.08.18
백준 1065번 풀이  (0) 2022.08.18
백준 15596번 풀이  (0) 2022.08.18

문제

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

 

11720번: 숫자의 합

첫째 줄에 숫자의 개수 N (1 ≤ N ≤ 100)이 주어진다. 둘째 줄에 숫자 N개가 공백없이 주어진다.

www.acmicpc.net

첫번째 줄에 숫자 개수, 두번째 줄에 공백 없이 붙은 숫자가 들어온다. 이 때 이 숫자들의 합을 구하시오.

 

풀이

import sys
a=int(sys.stdin.readline().strip())
b=sys.stdin.readline().strip()
for i in range(a):
    print(int(b[i]))

사실 문자열도 파이썬에서는 시퀀스 데이터로 쳐 주기 때문에, iteration이 가능하다. 즉, 문자열 길이만큼 반복문 때려박으면 된다.

import sys
a=int(sys.stdin.readline().strip())
b=sys.stdin.readline().strip()
sum=0
for i in range(a):
    sum=sum+int(b[i])
print(sum)

sum이라는 변수를 새로 만든 다음 합계를 계산, 반복문 다 돌리고 출력하면 끝.

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 1152번 풀이  (0) 2022.08.18
백준 10809번 풀이  (0) 2022.08.18
백준 1065번 풀이  (0) 2022.08.18
백준 15596번 풀이  (0) 2022.08.18
백준 4344번 풀이  (0) 2022.08.18

문제

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

 

1065번: 한수

어떤 양의 정수 X의 각 자리가 등차수열을 이룬다면, 그 수를 한수라고 한다. 등차수열은 연속된 두 개의 수의 차이가 일정한 수열을 말한다. N이 주어졌을 때, 1보다 크거나 같고, N보다 작거나

www.acmicpc.net

1부터 n(입력하는 정수)까지 중 한수가 몇 개인지 출력하면 되는 문제. 한수는 각 자릿수가 등차수열인 수를 말한다. (예: 123) 공차가 양수건 음수건 0이건 걍 일정하면 된다.

 

풀이

일단 등차수열인지를 봐야 하는거라서 한자리와 두자리는 그냥 한수로 쳐준다. 두자리 수의 경우 공차가 하나밖에 없기 때문. 한자리는 뭐지 특별채용? 그래서 처리를 두 개 해야 한다.

  1. 100보다 큰가?
  2. 한수인가? (각 자리수의 차가 일정한가?)

참고로 이번 풀이는 for랑 while 둘 다 있다. 제출은 for로 했지만. 사실 반복문의 특성에 따라 코드가 좀 다르다뿐이지 기본적인 로직은 같고.

 

For

han_count=0
for i in range(111):
    if i < 100:
        han_count += 1
    else: 
        for j in str(i):
            print(j)

일차적으로 한자리/두자리는 한수이므로 묻따않 세주는 처리를 할 것이다. (range가 111인 이유는 그래야 110까지 나와서) 일단 100보다 클 경우 문자열화하고 자릿수를 나누게끔 했는데, 문제가 하나 있었다. 이거 이렇게 해놨는데 인덱싱이 안된다.

han_count=0
han_list=[]
for i in range(1,111):
    if i < 100:
        han_count += 1
        han_list.append(i)
    else: 
        k = i // 100 # 100의 자리 
        m = (i % 100) // 10 # 10의 자리
        n = i % 10 # 일의 자리
        if k - m == m - n:
            han_count += 1
            han_list.append(i)
        else: 
            han_count += 0
print(han_count)
print(han_list)

그래서 자리수 직접 계산해서 뽑았다. 참고로 1부터인 이유는 문제에서 제일 작은 수가 1이라서. 근데 저거 생각해보니까 1000이 빠졌는데 어 잠깐

import sys
a=int(sys.stdin.readline())
han_count=0
for i in range(1,a+1):
    if i < 100:
        han_count += 1
    else: 
        k = i // 100 # 100의 자리 
        m = (i % 100) // 10 # 10의 자리
        n = i % 10 # 일의 자리
        if k - m == m - n:
            han_count += 1
        else: 
            han_count += 0
print(han_count)

근데 우리가 입력을 해야 하잖음? 그래서 준비했습니다. sys.stdin.readline()이다. 아예 정수 처리까지 했다.

import sys
a=int(sys.stdin.readline())
han_count=0
for i in range(1,a+1):
    if i < 100:
        han_count += 1
    elif i == 1000: 
        han_count += 0
    else: 
        k = i // 100 # 100의 자리 
        m = (i % 100) // 10 # 10의 자리
        n = i % 10 # 일의 자리
        if k - m == m - n:
            han_count += 1
        else: 
            han_count += 0
print(han_count)

1000에 대한 처리는 이쪽. (1000은 한수가 아니다)

 

While

j=1
while j <= a:
    if j < 100:
        han_count += 1
    else: 
        k = j // 100 # 100의 자리 
        m = (j % 100) // 10 # 10의 자리
        n = j % 10 # 일의 자리
        if k - m == m - n:
            han_count += 1
        else: 
            han_count += 0
    j += 1

while은 for와는 맥락이 다른 반복문이다. 반복하는 거 자체는 똑같은데, 얘는 조건부 반복문이라서 최솟값 잡고 반복문 반복할때마다 계속 더하면서 위의 저 로직(100보다 큰가? 한수인가?)을 거치게 하면 된다.

import sys
a=int(sys.stdin.readline())
han_count=0
j=1
while j <= a:
    if j < 100:
        han_count += 1
    else: 
        k = j // 100 # 100의 자리 
        m = (j % 100) // 10 # 10의 자리
        n = j % 10 # 일의 자리
        if k - m == m - n:
            han_count += 1
        else: 
            han_count += 0
    j += 1
print(han_count)

그래서 이렇게 된다.

import sys
a=int(sys.stdin.readline())
han_count=0
j=1
while j <= a:
    if j < 100:
        han_count += 1
    elif j == 1000: 
        han_count += 0
    else: 
        k = j // 100 # 100의 자리 
        m = (j % 100) // 10 # 10의 자리
        n = j % 10 # 일의 자리
        if k - m == m - n:
            han_count += 1
        else: 
            han_count += 0
    j += 1
print(han_count)

1000에 대한 처리까지 하면 이렇게 된다. (1000은 한수가 아님)

'BOJ > [BOJ] Python' 카테고리의 다른 글

백준 10809번 풀이  (0) 2022.08.18
백준 11720번 풀이  (0) 2022.08.18
백준 15596번 풀이  (0) 2022.08.18
백준 4344번 풀이  (0) 2022.08.18
백준 8958번 풀이  (0) 2022.08.18

Profile

Lv. 34 라이츄

요즘 날씨 솔직히 에바참치김치꽁치갈치넙치삼치날치기름치준치학꽁치임..