PS/Codeforces

Codeforces Round 931 (Div. 2)

Still Young 2024. 3. 6. 19:42

A. Too Min Too Max(링크)

접근 방법

수식적으로 증명하는 방법이 있으나, A인 만큼 빠르게 직관으로 접근해보았다.

4개의 숫자, a, b, c, d가 있다고 하자.

이 때, 차례로 이웃한 숫자와의 차이가 가장 크게 만들면 된다.

그렇다면 a, b, c, d를 가장 큰 수, 가장 작은 수를 반복해서 넣으면 된다는 생각으로 이어진다.

Solution

수열을 정렬한 후 a, b, c, d를 차례로 (가장 큰 수) (가장 작은 수) (두번째로 큰 수) (두번째로 작은 수)로 하여 문제에서 말하는 수식을 풀면 된다.

 

import sys

input = sys.stdin.readline
sys.setrecursionlimit(int(1e9))

T = int(input())

while T:
    T -= 1

    _ = input()
    arr = sorted(list(map(int, input().split())))

    print(
        abs(arr[0] - arr[-1])
        + abs(arr[-1] - arr[1])
        + abs(arr[1] - arr[-2])
        + abs(arr[-2] - arr[0])
    )

B. Yet Another Coin Proble(링크)

접근 방법

이 문제는 꽤나 고생했던 문제이다.

우선, 만약 모든 동전들이 1, 10, 100, 1000, 10000 등과 같이 금액 동전으로 항상 큰 금액 동전을 만들 수 있는 경우라면 greedy하게 큰 동전부터 최대로 사용하는 방식을 택하면 된다.

하지만, 이번 문제의 경우 동전의 금액이 1, 3, 6, 10, 15으로, 앞선 문제와는 다른 관계이다.

Solution 1. 내가 푼 방법(DP)

우선 내가 푼 방식은 어찌 됐던, 모든 동전의 최소 공배수는 30원이기 때문에, 30원은 15원이 가장 빠르게 만든다.

문제는 30으로 나눴을 때의 나머지 금액인데, 이 때는 DP를 이용하여 계산했다.

어차피 for 문 30번만 돌면 DP 값을 다 구할 수 있으므로, O(t)에 문제를 해결할 수 있다.

 

import sys

input = sys.stdin.readline
sys.setrecursionlimit(int(1e9))

T = int(input())

dp = [0] + [-1] * int(29)
for i in range(0, 30):
    if i + 1 < 30:
        if dp[i+1] == -1:
            dp[i+1] = dp[i] + 1
        else:
            dp[i+1] = min(dp[i+1], dp[i] + 1)
    if i + 3 < 30:
        if dp[i+3] == -1:
            dp[i+3] = dp[i] + 1
        else:
            dp[i+3] = min(dp[i+3], dp[i] + 1)
    if i + 6 < 30:
        if dp[i+6] == -1:
            dp[i+6] = dp[i] + 1
        else:
            dp[i+6] = min(dp[i+6], dp[i] + 1)
    if i + 10 < 30:
        if dp[i+10] == -1:
            dp[i+10] = dp[i] + 1
        else:
            dp[i+10] = min(dp[i+10], dp[i] + 1)
    if i + 15 < 30:
        if dp[i+15] == -1:
            dp[i+15] = dp[i] + 1
        else:
            dp[i+15] = min(dp[i+15], dp[i] + 1)

while T:
    T -= 1
    n = int(input())
    ans = n
    if n < 30:
        print(dp[n])
    else:
        ans = min(n // 15 + dp[n % 15], n // 15 - 1 + dp[n%15 + 15])
        print(ans)

2. Editorial 방법(Bruteforce)

Editorial에서는 좀 더 Naive한 방법을 소개하는데, 이 방식에서는 각 동전이 최대로 사용될 수 있는 개수를 한정하는 방식이다.

즉, a 동전이 b 동전이 만들 지 못하는 최대 개수까지 사용되는 것이다.

이 방식을 택하면 각 동전은 최대 다음 개수만 사용해도 된다는 것을 알 수 있다.

  • 1원: 2개
  • 3원: 1개
  • 6원: 4개
  • 10원: 2개

따라서, 총 for문 3 * 2 * 5 * 3 번 돌면서 정답을 구하면 된다.

C. Find a Mine

접근 방식

처음 풀어보는 Interactive 문제이다.

그래서인지, 매우 고생했고, 시간 안에 해결하지 못했다.

문제를 읽고 가장 먼저 발견한 직관은, 어떤 점을 기준으로 query 했을 때, 출력하는 거리는 query 한 점을 기준으로 45도 회전한 정사각형 내에 정답이 있다는 것이다.

따라서, 만약 꼭지점 중 한 곳에서 query를 한다면, 맨허튼 거리 d인 대각선 내에 정답이 존재한다는 것이다.

Solution

꼭지점 중 한 곳에서 쿼리를 먼저 한다.

이후에, 해당 대각선의 양 끝에서 쿼리를 날린 후 각 꼭지점에서 말하는 거리만큼 떨어진 대각선 위의 점을 쿼리하면 총 4번만에 찾을 수 있다.

이 때, 양 끝 점에서 쿼리를 하는 이유는 한 쪽 대각선 끝을 기준으로 대각선 위의 지뢰보다 더 가까운 지뢰가 존재할 수 있기 때문이다.

 

import sys

input = sys.stdin.readline
sys.setrecursionlimit(int(1e9))

T = int(input())

def check(x, y):
    print(f"? {x} {y}")
    sys.stdout.flush()
    dist = int(input())
    if dist == 0:
        print(f"! {x} {y}")
        sys.stdout.flush()
        return True, dist
    return False, dist


while T:
    T -= 1
    m, n = map(int, input().split())

    is_match, dist = check(1, 1)
    
    if is_match:
        continue

    dx = min(m - 1, dist)
    dy = min(n - 1, dist)

    is_match, dist1 = check(1 + dx, 1 + dist - dx)

    if is_match:
        continue

    is_match, dist2 = check(1 + dist - dy, 1 + dy)

    if is_match:
        continue

    is_match, _ = check(1 + dx - dist1//2, 1 + dist - dx + dist1//2)

    if is_match:
        continue

    print(f"! {1 + dist - dy + dist2//2} {1 + dy - dist2//2}")
    sys.stdout.flush()

'PS > Codeforces' 카테고리의 다른 글

Codeforces Round 932 (Div. 2)  (1) 2024.03.09
Codeforces Round 930 (Div. 2)  (0) 2024.03.09