1. D번
D - Escape Route
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
atcoder.jp
2차원 배열이 주어질때, 각 위치에서 탈출구 E번까지 가는 최단 경로를 표시해야하는 문제
#은 이동불가능 지역이므로 표시하지 않는다.
..E
...이라고 한다면?
>>E
>>^ 이런식으로 될 것이다.
혹은 정답이 여러개일 수 있는데
>>E^>^도 정답이 될듯?
각각의 지점에서 E까지 가는 최단 경로를 어떻게 찾는다고 하더라도 표시를 어떻게 해야하지?
각각의 지점이 1000*1000개인데 이걸 언제 다하냐?
그러면 반대로 생각해서 E에서 출발해서 각 지점까지 BFS로 그래프 탐색을 한다면..?
탐색하면서 각 지점에 이동 방향 표시를 해줌
그러면 그 이동방향 표시는 E에서 각 지점까지의 최단 경로 표시가 된다
그리고 이 이동방향 표시를 다시 반대로 바꿔주면 된다
처음에 모든 지점을 탐색해서 E의 좌표를 모두 큐에 넣고 BFS를 수행하면서 각 지점까지 이동방향 표시를 해주고,
마지막에 다시 모든 지점을 탐색해서 이동방향 표시가 된 지점을 반대 방향으로 바꿔줌
>은 <으로 ^은 V으로
from collections import deque
h,w = map(int,input().split())
S = [list(input()) for _ in range(h)]
queue = deque([])
visited = [[0]*w for _ in range(h)]
for y in range(h):
for x in range(w):
if S[y][x] == 'E':
queue.append((x,y))
visited[y][x] = 1
delta = [[0,1],[1,0],[0,-1],[-1,0]]
char = ['v','>','^','<']
reverse = ['^','<','v','>']
while queue:
x,y = queue.popleft()
for i in range(4):
a,b = delta[i]
dx = x + a
dy = y + b
if dx >= 0 and dx <= w-1 and dy >= 0 and dy <= h-1 and S[dy][dx] == '.' and visited[dy][dx] == 0:
visited[dy][dx] = 1
queue.append((dx,dy))
S[dy][dx] = char[i]
for y in range(h):
for x in range(w):
for i in range(4):
if S[y][x] == char[i]:
S[y][x] = reverse[i]
break
for row in S:
print(''.join(row))
혹은 BFS하면서, 아예 반대방향으로 표시해둔다면, 마지막에 다시 방향을 바꿀 필요는 없겠지
from collections import deque
h,w = map(int,input().split())
S = [list(input()) for _ in range(h)]
queue = deque([])
visited = [[0]*w for _ in range(h)]
for y in range(h):
for x in range(w):
if S[y][x] == 'E':
queue.append((x,y))
visited[y][x] = 1
delta = [[0,1],[1,0],[0,-1],[-1,0]]
reverse = ['^','<','v','>']
while queue:
x,y = queue.popleft()
for i in range(4):
a,b = delta[i]
dx = x + a
dy = y + b
if dx >= 0 and dx <= w-1 and dy >= 0 and dy <= h-1 and S[dy][dx] == '.' and visited[dy][dx] == 0:
visited[dy][dx] = 1
queue.append((dx,dy))
S[dy][dx] = reverse[i]
for row in S:
print(''.join(row))
2. E번
E - Fruit Lineup
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
atcoder.jp
사과, 오렌지, 바나나, 포도가 a,b,c,d개 있다.
이들을 일렬로 배열하고자 하는데, 다음과 같은 조건을 만족해야한다.
모든 사과는 모든 바나나의 왼편에 있어야한다.
모든 사과는 모든 포도의 왼편에 있어야한다.
모든 오렌지는 모든 포도의 왼편에 있어야한다.
사과, 오렌지, 바나나, 포도는 각각 구별할 수 없는, 동일한 과일들 이라고 할때, 조건을 만족하면서 배열하는 경우의 수는?
----------------------------------------------------------------------------------------------------------------------------
포도 왼쪽에 사과 오렌지가 있어야하기 때문에
(사과, 오렌지) ||||| (포도)
이런 형태가 되어야한다.
이 상태에서 바나나의 배치가 중요한데, 가장 왼쪽에 있는 포도를 기준으로
그 왼쪽에 i = 0,1,2,...,C개의 바나나가 있다고 하자.
(사과 A개, 오렌지 B개, i개의 바나나) (포도) (포도 D-1개,바나나 C-i개) 이런 형태
그러면 (사과 A개, 오렌지 B개, i개의 바나나)을 일렬로 배열하는 경우의 수는?
여기서 사과, 오렌지, 바나나 각각은 구별할 수 없는 과일이라는 점에 주목해야한다.
그러니까 각각은 순열해봤자 동일하다는 거
그리고 모든 사과는 바나나의 왼편에 있어야한다는거
그러면 A개의 사과와 i개의 바나나를 일단 배열하고 그 사이사이 빈칸(빨간, 주황부분)에 오렌지 B개를 넣으면 된다.

그러면 빨간색 표시 A개, 주황색 표시 i+1개라서 사이사이가 A+i+1개인데, 여기에 B개의 오렌지를 넣는다면?
A+i+1개의 자리 중 B개의 자리를 선택해 각각을 집어넣으면 되니까 A+i+1 C B가지?
그건 아니고
1자리에 여러개의 오렌지를 넣어도 된다
이렇게도 되잖아

그래서 A+i+1개중 B개의 자리를 중복해서 선택하는 중복조합 A+i+1HB가지
nHr = n+r-1Cn-1
n명 중 k명을 중복해서 선택하는 중복조합의 수 이해하기
n명 중 k명을 중복해서 선택하는 중복조합의 수 이해하기
1. 중복조합 n종류가 있을 때, k개를 선택하는데 종류의 중복을 허용해서 선택하는 방법의 수를 구하고 싶다. 예를 들어 a,b,c 3개의 문자 중 5개를 중복을 허용해서 선택한다면 (a,a,a,a,a) (a,a,a,a
deepdata.tistory.com
이는 A+i+1+B-1 C A+i가지와 같다.
그러면 두번째로
(사과 A개, 오렌지 B개, i개의 바나나) (포도) (포도 D-1개,바나나 C-i개) 이런 형태
포도 왼편은 구했으니까 오른편 (포도 D-1개, 바나나 C-i개)를 배열하는 방법의 수는?
포도와 바나나는 자유롭게 배열할 수 있으므로, 포도 D-1개, 바나나 C-i개를 일렬로 배열하는 복수 순열의 개수와 같다.
이는 (C-i+D-1)! / ((C-i)!(D-1)!)가지
팩토리얼(factorial)의 소수 모듈로 곱셈의 역원(modulo inverse)을 구하는 기본적인 테크닉
팩토리얼(factorial)의 소수 모듈로 곱셈의 역원(modulo inverse)을 구하는 기본적인 테크닉
이미 알고있는 것들인데 블로그에 정리가 안되어 있어서 1. n!을 소수 p로 나눈 나머지 소수 p에 대하여 $n! mod p$를 구하는 문제가 있다. 단 하나의 $n! mod p$를 구해야한다면... $n! = n*(n-1)*(n-2)*...*1$
deepdata.tistory.com
팩토리얼의 소수 998244353 모듈로 곱셈의 역원과 팩토리얼 모듈로 값을 모두 미리 구해놓는다면 빠르게 구할 수 있다
a,b,c,d = map(int,input().split())
mod = 998244353
#팩토리얼, 팩토리얼 역원 모두 구해놓기
n = a+b+c+d
factorial = [0]*(n+1)
factorial[0] = 1
for i in range(1,n+1):
factorial[i] = factorial[i-1]*i
factorial[i] %= mod
factorial_inverse = [0]*(n+1)
factorial_inverse[n] = pow(factorial[n], mod-2, mod)
for i in range(n,0,-1):
factorial_inverse[i-1] = factorial_inverse[i] * i
factorial_inverse[i-1] %= mod
#a+b+iCb * (c-i+d-1)!/(d-1)!(c-i)!을 i = 0,1,,...,c에 대해 모두 합해줌
count = 0
for i in range(c+1):
v1 = factorial[a+b+i]*factorial_inverse[b]*factorial_inverse[a+i]
v1 %= mod
v2 = factorial[c-i+d-1]*factorial_inverse[d-1]*factorial_inverse[c-i]
v2 %= mod
count += v1*v2
count %= mod
print(count)
'경쟁 프로그래밍 > Atcoder' 카테고리의 다른 글
| AtCoder Beginner Contest 406 대충 복기(증가하다가 감소하는 수열의 개수) (0) | 2025.05.18 |
|---|---|
| ABC 357 C번 복기 - 시에르핀스키 패턴 그리는 재귀 연습 (0) | 2024.06.11 |
| ABC 350 D번 복기 - 직접 연결되어있지는 않지만 도달할 수 있는 경로의 개수 구하는법 (0) | 2024.04.21 |
| ABC 348 D번 복기 - 그래프를 재구성하고 BFS/DFS를 해야하는 문제 (0) | 2024.04.10 |
| ABC 340 F번 복기 - 확장 유클리드 알고리즘 제대로 활용하기 (0) | 2024.02.21 |