처음에 문제 이해를 잘못했었는데, 차분히 잘 생각해보니까 어느정도 구조가 눈에 보이기 시작했다.

 

즉, 주어진 "N 이하의 예쁜 수들로" N을 어떻게 만들 수 있을까? 라는 문제가 되겠다.

import math
N, K = map(int,input().split())

pretty_number = []
for i in range (1, N + 1):
    str_i = str(i)
    n = len(str_i)
    summary = 0
    for j in range (n):
        summary += int(str_i[j])
    if i % summary == 0:
        pretty_number.append(i)

dp = [0 for _ in range (0, N + 1)]

for i in range (0, len(pretty_number)):
    dp[pretty_number[i]] += 1
    for j in range (pretty_number[i] + 1, N + 1):
        dp[j] += dp[j - pretty_number[i]]
print(dp[-1] % K)

 

방식 자체는 굉장히 냅색 문제와 유사하게 되겠습니다.

 

굉장히 그리디하게 풀면 될 것 같은 느낌 (경우의 수를 구하는 경우에서는 특히 브루트포스로 구해도 될 것 같다)

 

답안 코드는 이하와 같다.

import sys 
from collections import defaultdict
input = sys.stdin.readline

N = int(input())
dict = {}
num = {}
for i in range (0,10):
    dict[i] = str(i)
    num[str(i)] = i
for i in range (0,26):
    dict[i + 10] = chr(i + 65)
    num[chr(i + 65)] = i + 10

summary = [0 for _ in range (0,36)]
#여기까지 기본 세팅
for _ in range (0,N):
    string =  input().rstrip()
    t = len(string)
    for i in range (0,t):
        summary[num[string[i]]] += (36 ** (t - i - 1))

K = int(input())

answer = 0

maximize = []
for i in range (0,36):
    maximize.append([dict[i], (35 - i) * summary[i]])

maximize.sort(key = lambda x: -x[1])


for i in range (0,K):
    answer += 35 * summary[num[maximize[i][0]]]

for i in range (K,36):
    answer += num[maximize[i][0]] * summary[num[maximize[i][0]]]


answer_string = []
while answer != 0:
    answer_string.append(dict[answer % 36])
    answer //= 36
    
answer_string = answer_string[::-1]
if answer_string != []:
    print("".join(s for s in  answer_string))
else:
    print("0")

 

(문제 사진이 안보인다... 어째서지)

 

 

문제 해결에 있어 주안점은 2가지가 되겠다.

 

1. 삼각형을 어떠한 방식으로 분할할 것인가? -> 정렬에 대한 이해 필요 / 회전체를 어떻게 분할 할 것인가?

 

2. 부피 공식의 구현

 

 

1.  x축에 대해서 회전을 시킬 경우, x축의 값에 따른 정렬

y축에 대해서 회전을 시킬 경우에는, y축의 값에 따른 정렬이 필요하겠다. 

정렬된 순서대로 부피를 구해주면 되겠다.

 

즉, (첫번째 - 두번째를 이은 직선으로 회전시켰을때) + (두번째 - 세번째를 이은 직선으로 회전시켰을 때) - (세번째 - 첫번째를 이은 직선으로 회전시켰을 때) 

 

2. 부피 공식의 구현에 있어서는 케이스를 조금 나눌 필요가 있다.

x좌표 혹은 y좌표가 같은지 확인할 필요가 있다. (두점이 주어졌을 때 직선의 방정식을 세워보게 되면, 두 점의 x좌표 혹은 y좌표가 같은 경우에는 직선의 방정식에서의 분모가 0이 되는 경우가 발생할 수 있으므로, ZeroDivisor Error가 나올 수 있겠다.)

이때는 그냥 깡구현으로 하면 되겠다. (사실 정적분이니까..)

 

해답은 다음과 같겠다.

import sys
import copy
import math
input = sys.stdin.readline

x1,y1,x2,y2,x3,y3 = map(int,input().split())
pts = [[x1,y1],[x2,y2],[x3,y3]]

pts.sort(key = lambda x: x[0])
sort_x_pts = copy.deepcopy(pts)
#x좌표 기준으로 정렬

pts.sort(key = lambda x:x[1])
sort_y_pts = copy.deepcopy(pts)
#y좌표 기준으로 정렬

def partial_vol(pt1,pt2):
    x1,y1 = pt1[0], pt1[1]
    x2,y2 = pt2[0], pt2[1]

    axis_x_vol, axis_y_vol = 0,0
    if x1 == x2:
        #x축 좌표는 동일한 경우이므로, x축 기준으로 회전했을때는 0
        x = x1
        axis_y_vol = math.fabs(math.pi * (x ** 2) * (y2 - y1))
    elif y1 == y2:
        #y축 좌표는 동일한 경우이므로, y축 기준으로 회전했을때는 0
        y = y1
        axis_x_vol = math.fabs(math.pi * (y ** 2) * (x2 - x1))
    else:
        a = (y2 - y1) / (x2 - x1)
        b = (x2 * y1 - x1 * y2) / (x2 - x1)
        c = (x2 - x1) / (y2 - y1)
        d = (y2 * x1 - x2 * y1) / (y2 - y1)

        axis_x_vol = math.fabs((x2 ** 3 - x1 ** 3) * (a ** 2 / 3) + (x2 ** 2 - x1 ** 2) * (a * b) + (x2 - x1) * b ** 2) * math.pi
        axis_y_vol = math.fabs((y2 ** 3 - y1 ** 3) * (c ** 2 / 3) + (y2 ** 2 - y1 ** 2) * (c * d) + (y2 - y1) * d ** 2) * math.pi
    return axis_x_vol, axis_y_vol

answer_x = math.fabs(partial_vol(sort_x_pts[0], sort_x_pts[1])[0] + partial_vol(sort_x_pts[1], sort_x_pts[2])[0] - partial_vol(sort_x_pts[2], sort_x_pts[0])[0])
answer_y = math.fabs(partial_vol(sort_y_pts[0], sort_y_pts[1])[1] + partial_vol(sort_y_pts[1], sort_y_pts[2])[1] - partial_vol(sort_y_pts[2], sort_y_pts[0])[1])

print(answer_x, answer_y)

 

1부터 K까지 prime에 해당된 소수를 전부 곱했을 때, 해당 소수(prime)의 지수를 묻는 것과 동일하게 볼 수 있겠다.

이하는 코드가 되겠다.

 

import math
import sys
from collections import defaultdict
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline

N = int(input())
prime = list(map(int,input().split())) #prime의 길이가 N
K = int(input())

answer = 0
for i in range (0,N):
    cnt = 0
    num = K
    while num > 1:
        cnt += (num // prime[i])
        num //= prime[i]
    answer += cnt
print(answer)

 

 

 

 

Well-known인 다익스트라 알고리즘. ...

 

처음에 실수로 가중치가 왕복으로 주어지는줄 알았는데, 그게 아니라 편도였던 것....

 

수정하니 바로 맞는 결과가 나왔다.

import sys
import heapq
input = sys.stdin.readline
N = int(input())
M = int(input())
gp = [[] for _ in range (0,N+1)]
for _ in range (0,M):
    a,b,cost = map(int,input().split())
    gp[a].append((b,cost))
start, end = map(int,input().split())
INF = int(1e9)
dist = [INF for _ in range (0,N+1)]
q = []
dist[start] = 0
heapq.heappush(q, (dist[start], start))
while q:
    distance, node = heapq.heappop(q)
    if dist[node] < distance:
        continue
    for next, next_dist in gp[node]:
        d = distance + next_dist
        if d < dist[next]:
            dist[next] = d
            heapq.heappush(q, (dist[next], next))
print(dist[end])

 

문제 기준에 따라서 열심히 계산해주면 될 것 같다.

학생의 번호가 1~100 / 추천 횟수가 1000회 이하이므로 100 x 1000을 해도 연산에 있어 어려움은 없을 것 같다.

 

답안 코드는 다음과 같다.

import sys
from collections import defaultdict
input = sys.stdin.readline
N = int(input()) #사진틀의 개수
m = int(input())
rcd = list(map(int,input().split()))
candidate = defaultdict(int)
date = defaultdict(int) 
cnt = 0 #사진틀의 현재 갯수
for i in range (0,m):
    #사진첩에 걸린 후보수가 N에 도달했는지 확인
    if len(list(candidate.keys())) < N:
        candidate[rcd[i]] += 1
        if date[rcd[i]] == 0:
            date[rcd[i]] = i + 1 #시점 등록     
    else: #사진첩에 걸린 후보수가 N인 경우            
        if candidate[rcd[i]] == 0:#날짜 초기화도 해야함
            number = list(candidate.keys())
            removing = [] #없앨 후보자
            min_vote = int(1e9)
            for num in number:
                if candidate[num] != 0:
                    min_vote = min(min_vote, candidate[num])
            for num in number:
                if candidate[num] == min_vote:
                    removing.append((num, date[num]))
            removing.sort(key = lambda x : x[1])
            del_candidate, _ = removing[0][0], removing[0][1]
            candidate[del_candidate] = 0
            candidate[rcd[i]] += 1 
            date[del_candidate] = 0
            date[rcd[i]] = i + 1
        else:
            candidate[rcd[i]] += 1
            
number = list(candidate.keys())
answer = []
for num in number:
    if candidate[num] != 0:
        answer.append(num)
answer.sort()
print(*answer)

 

 

 

N, T, A라는 숫자가 주어지고, A와 T는 각각 현재 득표수를 나타내는 상황이며  N은 총 표수를 나타낸다.

이때 이 선거의 결과 여부를 판단하는 문제가 되겠다.

남아있는 표수를 구한 뒤, 케이스를 나눠 계산해주면 되겠다.

import sys
input = sys.stdin.readline

n,t,a = map(int,input().split())
remain = n - t - a
if t <= a:
    if t + remain < a:
        print("Yes")
    else:
        print("No")
elif a <= t :
    if a + remain < t:
        print("Yes")
    else:
        print("No")

 

 

 

 

주어진 문자열을 규칙에 맞게 출력해주면 되겠다.

즉, 아래에서부터 위로 읽어주는건데 (f->d->a... 순), 마지막에 딸려있는 공백은 읽지 않고,

중간에 껴있는 공백은 *를 넣어주면 되겠고, 해당 코드는 아래와 같이 나오겠다.

import sys
input = sys.stdin.readline

N = int(input())
max_length = -1
word = []
for _ in range (0,N):
    s = input().rstrip()
    word.append(s)
    max_length = max(max_length, len(s))
new_word = []
for i in range (0,N):
    new_s = word[i] + (max_length - len(word[i])) * "*"
    new_word.append(new_s)

answer = []

for i in range (0,max_length):
    word = ""
    cnt = 0
    for j in range (N-1,-1,-1):
        if new_word[j][i] != "*":
            word += cnt * "*"
            word += new_word[j][i]
            cnt = 0
        else:
            cnt += 1
    answer.append(word)
    
for ans in answer:
    print(ans)

 

 

 

 

 

 

 

주어진 쿼리에 따라서 명령어를 수행하면 되겠다.

 

1은 볼을 넣고, 

2는 볼을 빼고, (반드시 있다는 것이 보장)

3은 현재 숫자가 쓰여있는 볼의 종류 갯수 출력

 

딕셔너리를 사용하면 더욱 간편하게 풀 수 있는 것 같다. (시간복잡도도 굉장히 좋기때문)

 

import sys
from collections import defaultdict
input = sys.stdin.readline


Q = int(input())
d = defaultdict(int)
cnt = 0
def f(cmd):
    global d
    global cnt
    if len(cmd) == 1: #케이스 3의 경우
        print(cnt)  #cnt가 갯수를 뜻하겠다
    elif len(cmd) == 2:
        if cmd[0] == 1: #케이스 1의 경우
            d[cmd[1]] += 1
            if d[cmd[1]] == 1:
                cnt += 1
        elif cmd[0] == 2: #케이스 2의 경우
            d[cmd[1]] -= 1
            if d[cmd[1]] == 0:
                cnt -= 1
                
for _ in range (0,Q):
    cmd = list(map(int,input().split()))
    f(cmd)

 

 

3차원 prefix 문제가 되겠다.

3차원의 직육면체를 분할해서 생각해보면 좋을 것 같다.

 

import sys
from collections import defaultdict
input = sys.stdin.readline

N = int(input())
num = [[[0 for _ in range (0,N+1)] for _ in range (0,N+1)] for _ in range (0,N+1)]
for i in range (0,N):
    for j in range (0,N):
        a = list(map(int,input().split()))
        for k in range (0,N):
            num[i+1][j+1][k+1] = a[k]
prefix = [[[0 for _ in range (0,N+1)] for _ in range (0,N+1)] for _ in range (0,N+1)]
for i in range (1,N+1):
    for j in range (1, N+1):
        for k in range (1,N+1):
            prefix[i][j][k] = prefix[i][j][k-1] + prefix[i][j-1][k] + prefix[i-1][j][k] - prefix[i-1][j-1][k] - prefix[i-1][j][k-1] - prefix[i][j-1][k-1] + prefix[i-1][j-1][k-1] +num[i][j][k]

Q = int(input())
for _ in range (0,Q):
    l_x,r_x,l_y,r_y,l_z,r_z = map(int,input().split())
    l_x,l_y,l_z = l_x-1, l_y-1, l_z-1
    answer = prefix[r_x][r_y][r_z] - prefix[l_x][r_y][r_z] - prefix[r_x][l_y][r_z] - prefix[r_x][r_y][l_z] + prefix[r_x][l_y][l_z]  + prefix[l_x][r_y][l_z]  + prefix[l_x][l_y][r_z]  - prefix[l_x][l_y][l_z]
    print(answer)

 

E,F는 수학쪽에 가까운 문제 같았는데 못 풀어서 상당히 아쉬웠다.

 

힘내서 풀어봐야겠다.

 

 

분리집합이라는 말을 들었을 때, Disjoint Set이라는 단어가 일단 생각이 났다.

 

아무리봐도 Intersection이 없는 집합들 이라고 생각할 수 있겠다.

 

사실 백준에서 문제 하나를 풀고 있었는데, 이거 태그가 분리집합이라서 ... 공부를 해야겠다고 생각하게 된듯.

 

즉, [1,2,3,4,5,6] 같은 집합이 주어져있을 때, 이들을 어떻게 묶을 것인지? 

 

어떻게 보면 Strongly Connected Component들이 구성되어있는가? 가 되겠다.

 

먼저 이러한 분리 집합을 생각함에 있어서 Union - Find라는 두개의 function을 통해서 정의된다.

 

첫번째로, Find (특정 원소가 어디에 소속되어있는지?)

 

def find(parent, x):
	if parent[x] != x:
    	return find(parent, parent[x])
    return x

 

이런 방식으로 재귀를 통해 x의 parent를 찾아가는 과정을 취한다.

 

다음으로는, 두개의 분리집합을 합치는 과정이 되고, Union이다.

def union(parent,a,b):
	a = find(parent, a)
    b = find(parent, b)
    if a < b:
    	parent[b] = a #작은쪽으로 맞추기 위해
    else:
    	parent[a] = b #작은쪽으로 맞추기 위해

 

이제 이러한 개념을 알아뒀으니 ,,,, 못풀었던 문제들을 해결하기 위해 떠나봐야겠다.

 

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

'스터디' 카테고리의 다른 글

4주차 스터디(23.12.01)-2  (1) 2023.12.01
4주차 스터디(23.12.01)  (1) 2023.11.30
3주차 스터디(23.11.24)  (0) 2023.11.30
2주차 스터디(23.11.16) - DFS, BFS  (0) 2023.11.11
1주차 스터디(23.11.09) - 완전 탐색 (Brute Force)  (0) 2023.11.07

+ Recent posts