728x90

백준 파이썬 공부 2025.04.05
6064번 카잉 달력 (실버 1)

1. 문제
최근에 ICPC 탐사대는 남아메리카의 잉카 제국이 놀라운 문명을 지닌 카잉 제국을 토대로 하여 세워졌다는 사실을 발견했다. 
카잉 제국의 백성들은 특이한 달력을 사용한 것으로 알려져 있다. 

그들은 M과 N보다 작거나 같은 두 개의 자연수 x, y를 가지고 각 년도를 <x:y>와 같은 형식으로 표현하였다. 
그들은 이 세상의 시초에 해당하는 첫 번째 해를 <1:1>로 표현하고, 두 번째 해를 <2:2>로 표현하였다. 

<x:y>의 다음 해를 표현한 것을 <x':y'>이라고 하자. 
만일 x < M 이면 x' = x + 1이고, 그렇지 않으면 x' = 1이다. 
같은 방식으로 만일 y < N이면 y' = y + 1이고, 그렇지 않으면 y' = 1이다. 
<M:N>은 그들 달력의 마지막 해로서, 이 해에 세상의 종말이 도래한다는 예언이 전해 온다.

예를 들어, M = 10 이고 N = 12라고 하자. 
첫 번째 해는 <1:1>로 표현되고, 11번째 해는 <1:11>로 표현된다. 
<3:1>은 13번째 해를 나타내고, <10:12>는 마지막인 60번째 해를 나타낸다.

네 개의 정수 M, N, x와 y가 주어질 때, <M:N>이 카잉 달력의 마지막 해라고 하면 
<x:y>는 몇 번째 해를 나타내는지 구하는 프로그램을 작성하라.

2. 입력
입력 데이터는 표준 입력을 사용한다. 

입력은 T개의 테스트 데이터로 구성된다. 
입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 

각 테스트 데이터는 한 줄로 구성된다. 
각 줄에는 네 개의 정수 M, N, x와 y가 주어진다. 
(1 ≤ M, N ≤ 40,000, 1 ≤ x ≤ M, 1 ≤ y ≤ N) 
여기서 <M:N>은 카잉 달력의 마지막 해를 나타낸다.

3. 출력
출력은 표준 출력을 사용한다. 
각 테스트 데이터에 대해, 정수 k를 한 줄에 출력한다. 
여기서 k는 <x:y>가 k번째 해를 나타내는 것을 의미한다. 
만일 <x:y>에 의해 표현되는 해가 없다면, 즉, <x:y>가 유효하지 않은 표현이면, -1을 출력한다.

4. 문제 해설
이건 정수론에 대해 어느 정도 알아야 풀이가 가능한 문제이다.
단순히 <1:1> 에서 부터 브루트 포스로 계산하려고 할 시에는 시간초과 엔딩이 난다.

<x:y> 일때, 이는 <(해당 해) % M : (해당 해) % N> 으로 나타낼 수 있다.
그 말을 식으로 작성하면,
answer = M * A1(나눗셈의 몫1) + x = N * A2(나눗셈의 몫2) + y
answer - x = M * A1 >> (answer - x) % M == 0
answer - y = N * A2 >> (answer - y) % N == 0
이걸 이용해보자

일단 가능한 마지막 해는 M과 N의 최소 공배수이고,
이 값을 넘어가면 해당 x, y에 해당하는 해는 존재하지 않는다고 보면 된다.
즉 -1

그리고 초기값을 x로 설정해 놓고 M을 더해가며,
각 값 - y가 N으로 나누어 떨어지는지 검사를 해가면 된다.

>> 코드

import sys

# 멸망의 해(마지막 해)를 구하기 위한 최대공약수와 최소공배수 함수
# 최대 공약수 함수
def gcd(x, y):
    if y == 0:
        return x
    else:
        return gcd(y, x%y)

# 최소 공배수 함수
def lcm(x, y):
    return x * y / gcd(x, y)

# 계산 함수
def calculate(M, N, x, y):
    # 초기 시작 값 x로 시작
    answer = x
    # 마지막 해 M, N의 최소 공배수로 설정
    max_value = lcm(M, N)
    # 해당값 - y가 N으로 나누어 떨어질 때까지 M 더하기
    while answer <= max_value:
        if (answer - y) % N == 0:
            return answer
        answer += M
    return -1

T = int(sys.stdin.readline().strip())
for _ in range(T):
    M, N, x, y = map(int, sys.stdin.readline().strip().split())
    
    print(calculate(M, N, x, y))


5. 문제 링크
https://www.acmicpc.net/problem/6064

728x90
728x90

백준 CPP 공부 2025.03.14
2798번 블랙잭 (브론즈 2)

1. 문제
카지노에서 제일 인기 있는 게임 블랙잭의 규칙은 상당히 쉽다. 
카드의 합이 21을 넘지 않는 한도 내에서, 카드의 합을 최대한 크게 만드는 게임이다. 
블랙잭은 카지노마다 다양한 규정이 있다.

한국 최고의 블랙잭 고수 김정인은 새로운 블랙잭 규칙을 만들어 상근, 창영이와 게임하려고 한다.

김정인 버전의 블랙잭에서 각 카드에는 양의 정수가 쓰여 있다. 
그 다음, 딜러는 N장의 카드를 모두 숫자가 보이도록 바닥에 놓는다. 
그런 후에 딜러는 숫자 M을 크게 외친다.

이제 플레이어는 제한된 시간 안에 N장의 카드 중에서 3장의 카드를 골라야 한다. 
블랙잭 변형 게임이기 때문에, 플레이어가 고른 카드의 합은 M을 넘지 않으면서 M과 최대한 가깝게 만들어야 한다.

N장의 카드에 써져 있는 숫자가 주어졌을 때, M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 구해 출력하시오.

2. 입력
첫째 줄에 카드의 개수 N(3 ≤ N ≤ 100)과 M(10 ≤ M ≤ 300,000)이 주어진다. 
둘째 줄에는 카드에 쓰여 있는 수가 주어지며, 이 값은 100,000을 넘지 않는 양의 정수이다.

합이 M을 넘지 않는 카드 3장을 찾을 수 있는 경우만 입력으로 주어진다.

3. 출력
첫째 줄에 M을 넘지 않으면서 M에 최대한 가까운 카드 3장의 합을 출력한다.

4. 코드

#include <iostream>
using namespace std;

int main(){
    int n, m;
    cin >> n >> m;
    
    int card[n];
    for (int i = 0; i<n; i++){
        cin >> card[i];
    }
    
    int result = 0;
    int sum;
    for (int i = 0; i<n-2; i++){
        for (int j = i+1; j<n-1; j++){
            for (int k = j+1; k<n; k++){
                sum = card[i] + card[j] + card[k];
                if (result < sum && sum <= m) result = sum;
            }
        }
    }
    cout << result << endl;
    return 0;
}



5. 문제링크
https://www.acmicpc.net/problem/2798

728x90
728x90

20240312 백준 파이썬 공부
18111번 마인크래프트

1. 문제
팀 레드시프트는 대회 준비를 하다가 지루해져서 샌드박스 게임인 ‘마인크래프트’를 켰다. 
마인크래프트는 1 × 1 × 1(세로, 가로, 높이) 크기의 블록들로 이루어진 3차원 세계에서 자유롭게 땅을 파거나 집을 지을 수 있는 게임이다.

목재를 충분히 모은 lvalue는 집을 짓기로 하였다. 
하지만 고르지 않은 땅에는 집을 지을 수 없기 때문에 땅의 높이를 모두 동일하게 만드는 ‘땅 고르기’ 작업을 해야 한다.

lvalue는 세로 N, 가로 M 크기의 집터를 골랐다. 집터 맨 왼쪽 위의 좌표는 (0, 0)이다. 
우리의 목적은 이 집터 내의 땅의 높이를 일정하게 바꾸는 것이다. 우리는 다음과 같은 두 종류의 작업을 할 수 있다.

좌표 (i, j)의 가장 위에 있는 블록을 제거하여 인벤토리에 넣는다.
인벤토리에서 블록 하나를 꺼내어 좌표 (i, j)의 가장 위에 있는 블록 위에 놓는다.
1번 작업은 2초가 걸리며, 2번 작업은 1초가 걸린다. 밤에는 무서운 몬스터들이 나오기 때문에 최대한 빨리 땅 고르기 작업을 마쳐야 한다. 
‘땅 고르기’ 작업에 걸리는 최소 시간과 그 경우 땅의 높이를 출력하시오.

단, 집터 아래에 동굴 등 빈 공간은 존재하지 않으며, 집터 바깥에서 블록을 가져올 수 없다. 
또한, 작업을 시작할 때 인벤토리에는 B개의 블록이 들어 있다. 땅의 높이는 256블록을 초과할 수 없으며, 음수가 될 수 없다.

2. 입력
첫째 줄에 N, M, B가 주어진다. (1 ≤ M, N ≤ 500, 0 ≤ B ≤ 6.4 × 107)

둘째 줄부터 N개의 줄에 각각 M개의 정수로 땅의 높이가 주어진다. (i + 2)번째 줄의 (j + 1)번째 수는 좌표 (i, j)에서의 땅의 높이를 나타낸다. 
땅의 높이는 256보다 작거나 같은 자연수 또는 0이다.

3. 출력
첫째 줄에 땅을 고르는 데 걸리는 시간과 땅의 높이를 출력하시오. 답이 여러 개 있다면 그중에서 땅의 높이가 가장 높은 것을 출력하시오.

>>>코드 1. 실패. 최대 높이를 256으로 설정하고 브루트 포스로 다 시간을 계산해봤지만 시간초과 및 틀림 

n, m, b = map(int, input().split()) # n, m, b 입력받기
ground = [] # 땅의 높이를 저장할 리스트 생성
for _ in range(n): # 땅의 높이 저장
    ground.append(list(map(int, input().split())))
time = [0] * 257 # 각 경우의 수에서 걸리는 시간을 검사할 리스트
for i in range(257): # 최대 높이까지 검사하고 시간 검사해보기
    for j in range(n):
        for k in range(m):
            if ground[j][k] > i: # 땅의 높이가 더 높으면 1당 2초 소요
                time[i] += (ground[j][k]-i) *2
            elif ground[j][k] < i: # 땅의 높이가 더 낮으면 1당 1초 소요
                time[i] += i-ground[j][k]
level = [] # 시간이 가장 적게 걸리는 땅의 높이를 저장할 리스트
for i in range(257): # 시간이 가장 적게 걸리는 것만 높이 저장
    if time[i] == min(time):
        level.append(i)
# 출력
print(min(time),level[-1])



블럭의 개수가 정해져 있으므로 정해진 블럭 수 이상으로 땅을 쌓을 수 없다.

>>>코드 2. 가능한 최대 높이를 더 제한해 줬다. 블럭의 개수가 정해져 있으므로 가능한 높이도 더 작게 정해진다

n, m, b = map(int, input().split()) # n, m, b 입력받기
ground = [] # 땅의 높이를 저장할 리스트 생성
for _ in range(n): # 땅의 높이 저장
    ground.append(list(map(int, input().split())))
# 총 블럭의 개수
block = b
for i in range(n):
    block += sum(ground[i])
pos = block // (n*m) # 가능한 최대의 높이
time = [0] * (pos+1) # 각 경우의 수에서 걸리는 시간을 검사할 리스트
for i in range(pos+1): # 최대 높이까지 검사하고 시간 검사해보기
    for j in range(n):
        for k in range(m):
            if ground[j][k] > i: # 땅의 높이가 더 높으면 1당 2초 소요
                time[i] += (ground[j][k]-i) *2
            elif ground[j][k] < i: # 땅의 높이가 더 낮으면 1당 1초 소요
                time[i] += i-ground[j][k]
level = [] # 시간이 가장 적게 걸리는 땅의 높이를 저장할 리스트
for i in range(pos+1): # 시간이 가장 적게 걸리는 것만 높이 저장
    if time[i] == min(time):
        level.append(i)
# 출력
print(min(time), level[-1])



성공

>>>문제 링크
https://www.acmicpc.net/problem/18111

728x90

+ Recent posts