본문 바로가기

문제풀이

2024년 5월 PS 일지

728x90

지금까지는 임의의 주기로 ps 일지를 작성했지만, 아마 이제부터는 꾸준히 ps일지가 올라올 예정이다. 언제까지 가능할지는 모르겠지만, 5월 셋째주부터 다이아 문제로만 스트릭을 잇는 것을 시도해 보고 있다.

2024년 6월 6일 기준

 

푼 문제 중 풀이가 기억이 나는 문제만 작성했다.

 

15773. Touch The Sky

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

더보기

고도 제약 조건을 다음과 같이 바꿀 수 있다.

  • 풍선을 사용했을 때 고도가 $L_i+D_i$ 이하이면 풍선을 사용할 수 있다.

그런데 이 문제는 deadline이 있는 스케줄링 문제와 동치이다. 따라서 deadline 오름차순으로 보면서 해당 풍선을 사용하고, 만약 사용으로 인해 해당 풍선이 deadline을 침범한다면 사용한 풍선 리스트에서 가장 $D$가 큰 풍선의 사용을 취소하는 그리디를 반복하면 최적해를 찾을 수 있다.

 

31818. Discount Event

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

내가 KAIST 알고리즘 동아리 RUN의 봄 대회에 낸 문제이다. 아마 공식 에디토리얼이 공개될 예정이므로, 여기서는 간단한 풀이만 서술한다.

더보기

경로를 세 가지로 나눌 수 있다.

  • 지름이 할인 행사가 적용된 정점을 지난다
  • 지름에서 할인 행사가 적용된 점 중 가장 가까운 점이 할인 행사가 적용된 정점 중 끝점이다
  • 위 두 경우 모두 아닌 경우

두 번째 경우는 dp를 사용해 처리할 수 있다. 각 정점에 대하여 그 정점을 루트로 하는 서브트리만 남겼을 때 정점을 구하는 dp를 짜면 된다.

 

첫 번째 경우와 세 번째 경우는 모두 sparse table로 할 수 있다. 구현 디테일이 좀 복잡하다

 

16182. Dumae

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

카이스트에서 두메를 시켜먹으면서 푼 문제이다

더보기

$u$에서 $v$로 가는 간선이 있다면 $L_v := max \{ L_v, L_u + 1\}$을 시행해도 무방하다. 위상정렬 순서대로 저 연산을 시행하여 모든 $u$에서 $v$로 가는 간선에 대해 $L_v \le L_u + 1$을 만족하도록 해 주자. 마찬가지로 $R_v$에 대해서도 똑같이 해 주자.

 

이제 각 $i$에 대해서 $[L_i, R_i]$ 사이에 있는 정수 하나씩을 겹치지 않게 배정해준다. $R_i$를 정렬하고 하면 된다. 만약 이것이 불가능하다면 해가 없다는 것을 증명할 수 있다.

 

16901. XOR MST

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

더보기

우선 mst에 msb가 켜진 간선이 두 개 이상 사용되었다고 가정하자. 그렇다면 두 간선을 중 한 간선을 제거하고 적절한 간선을 추가하는 방식으로 켜진 msb가 하나가 되는 해를 찾을 수 있다. 이렇게 하면 mst의 가중치가 감소하므로, 결국 mst에는 msb가 켜진 간선이 유일하다는 것을 알 수 있다.

 

따라서 msb가 켜진 집합과 꺼진 집합을 잇는 간선 중 가장 작은 가중치를 트라이로 찾고, msb가 켜진, 꺼진 집합 두 개에서 각각 재귀적으로 mst를 구해서 세 개를 합치면 된다.

 

23778. Lucky Shirt

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

더보기

셔츠들이 여러번 섞이게 되는데, 섞이는 과정의 최대 깊이가 특정한 고정된 값이라고 가정하면, 특별한 셔츠가 어느 위치에 가있을지에 대한 조건부 확률을 계산할 수 있다. (일단 최대 깊이로 섞이고 나면 그 전에 섞였던 것은 중요하지 않고, 특별한 셔츠가 특정 위치로 갈 확률이 다 같으므로 그 뒤로 섞이는 것도 중요하지 않아진다) 따라서 셔츠가 섞이는 최대 깊이에 따라 확률을 계산해 더해주면 된다.

 

28329. 바보 자물쇠

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

더보기

자물쇠의 상태 $S$에 대해 $i$보다 같거나 사전순으로 빠른 문자를 0으로 만들고, 그렇지 않은 문자를 1로 만든 배열을 $S_i$라 하자. $S$를 정렬하기 위해 필요한 최소 연산의 수는 $S_a, S_b, \cdots, S_z$를 정렬하기 위해 필요한 최소 연산 횟수의 합과 같다(zero-one principle). 변경 쿼리가 주어질 때 각 $S_i$에 대한 답은 흔히 금광세그라 불리는 세그먼트 트리로 처리할 수 있다.

 

17689. Candies

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

더보기

MCMF로 생각하면, 다음 두 가지 연산 중 가중치가 큰 것을 계속 반복하는 것이 최적이라는 것을 알 수 있다.

  • 선택된 사탕과 인접하지 않은 사탕을 선택한다. (xxx -> xox)
  • 선택되지 않은 사탕과 선택되지 않은 사탕이 반복하여 나타나는 부분을 반전한다. (xxoxoxx -> xoxoxox)

두 번째 연산의 경우, 연산을 시행해서 인접한 두 사탕이 선택될 수 있는 경우를 유의해야 한다.

이 과정을 빠르게 하려면 선택되지 않은 사탕과 선택된 사탕이 반복하여 나타나는 부분과, 그 부분을 반전했을 때 더해지는 가중치를 우선순위 큐 등의 자료구조에 저장해두는 것이다.

 

10717. 성벽

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

더보기

다음 두 dp값을 정의하고 계산한다.

$dp1[i][j]$를 $i$행 $j$열에서 오른쪽으로 뻗어나갈 수 있는 길이, 아래로 뻗어나갈 수 있는 길이의 최솟값이라 하자

$dp2[i][j]$를 $i$행 $j$열에서 왼쪽으로 뻗어나갈 수 있는 길이, 위 뻗어나갈 수 있는 길이의 최솟값이라 하자

 

이렇게 하면 각 $k$에 대해서, $i-j=k$를 만족하는 $i$행 $j$열 칸들에 대해 그 칸을 꼭짓점으로 하는 정사각형의 개수를 세그먼트 트리를 사용해 구할 수 있다. 처리가 좀 귀찮다.

 

16214. N과 M

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

더보기

답을 $X$라 하자. 또한, $X \equiv Y (\mod \phi (M))$라 하자.

오일러 정리에 의해 $N^X \equiv N^Y (\mod M)$이다. 따라서, $Y$만 구하면 $X$를 구할 수 있고, 재귀적으로 구하면 된다.

$N$이 $M$의 배수가 되는 등 약간의 예외처리가 필요하다.

 

17668. 시험

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

더보기

$Z \le X+Y$인 경우는 $X$와 $Y$조건만 만족하면 $Z$조건도 자동으로 만족한다. 이는 세그먼트 트리를 사용한 스위핑으로 풀 수 있다.

그렇지 않은 경우는 포함배제를 이용한다.$ | \{ (a, b, c) | a \le X, b \le Y, c \le Z \} | = | \{ (a, b, c) | b \le Y, c \le Z \} |+ | \{ (a, b, c) | a \le X, c \le Z \} | - | \{ (a, b, c) | c \le Z \} | $ 로 쓸 수 있고, 우변의 세 항들은 모두 변수가 2개 이하이므로 마찬가지로 세그먼트 트리를 사용한 스위핑으로 풀 수 있다.

 

1616. 드럼통 메세지

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

더보기

내가 열심히 쓴 설명보다 코드가 더 가독성이 좋다는 것을 발견해서 코드를 대신 올린다.

https://www.acmicpc.net/source/share/bae256814eb34e738037faca9d0cfe87

 

그런데 오일러서킷을 찾아서 푸는 다른 풀이도 있다고 한다. 사실상 동치인 것 같다.

 

19060. Secret Permutation

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

더보기

0, 1, 다른 모든 수 순서로 찾는다.

0: $(i, b, i)$ 쿼리를 넣어 결과가 $a$나 $b$가 아니라면 두 수 모두 0이 아니다. 인접한 수들끼리 쿼리를 넣어 걸러지지 않은 것만 모으자. 이후 모아진 수들에 대해서는 랜덤한 $a, b$를 골라서 $(x, a, b)$가 $b$가 나오는지 확인하여 아니라면 제거하는 방식을 반복해 한 수만 남기면 된다. $p_z =0$이라 하자.

1: $(a, b, z)$를 쿼리로 날려 $a$나 $b$가 아니라면 두 수 모두 1이 아니다. 이후 과정은 0을 찾는 것과 비슷하다. $p_o=1$이라 하자.

 

$(p^{-1}_{i-1}, o, o)$를 쿼리로 날리면 $p^{-1}_{i}$가 결과로 나온다.

 

15977. 조화로운 행렬

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

더보기

행렬의 column정렬해 첫 row를 $1, 2, \cdots , N$으로 맞추어도 좋다. 이렇게 하면 2차원 lis를 푸는 문제가 된다.

이후 lis처럼 dp를 정의하자. $dp[i]$는 $i$로 끝나는 최대길이 체인의 길이이다.

집합 $S_i$를 $dp[x] = i$인 $x$의 점들을 저장하는 집합으로 정의하자. std::set 등의 자료구조를 사용하여, $x$좌표가 증가하면 $y$좌표가 감소하는 점들만 남겨 관리해 주자.

이러면 각 $dp[i]$를 구할 때 이분탐색으로 풀 수 있다. $dp[i] \le x$라면 집합 $S_{x-1}$에 $i$번째 점 왼쪽 아래에 위치하는 점이 있을 것이다.

 

14866. 산만한 고양이

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

더보기

정점을 제거했을 때 몇 개의 컴포넌트로 나뉘는지만 알면 $v-e+f=c$공식을 써서 풀 수 있다. dfs트리에서 한 정점을 제거했을 때 제거된 정점의 자식 서브트리들에 대해 부모 서브트리와 연결되어 있는지 여부를 바탕으로 컴포넌트 개수를 구할 수 있다.

 

19619. 자매 도시

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

더보기

쿼리가 오프라인이라면 답에 대한 이분탐색을 할 수 있다. 한 $x$에 대해 $x$ 이하의 가중치를 갖는 간선만 생각하자.

두 정점이 연결되어 있고 차수가 3인 정점이 있거나 두 정점을 포함하는 컴포넌트가 트리가 아니면 된다.

세 가지 모두 union-find로 할 수 있는데, 쿼리가 온라인이므로 이를 persistent하게 관리하면 된다.

 

16907. 서로 다른 부분 문자열 쿼리

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

(설명은 아직 작성 중이다)

더보기

완성된 문자열을 뒤집은 문자열을 $S$라 하자. 그러면 해야 하는 것은 $S$의 각 suffix들에 대해 suffix에 포함되는 서로 다른 부분 문자열 개수를 구해야 한다.

 

일단 SA와 LCP array를 구해주자. 그러면 $i$번째 suffix에 대한 답을 알고 있을 때 $i-1$번째 suffix에 대한 답을 구할 수 있다. 

728x90

'문제풀이' 카테고리의 다른 글

2025 KSA Automata Winter Contest 후기  (0) 2025.02.16
2024년 6월 PS 일지  (2) 2024.07.01
5월 6일 연습 (Romanian Master of Informatics 2021)  (0) 2023.05.06
5월 4일 연습  (0) 2023.05.04
4월 29일 연습 (JOI 2016)  (0) 2023.04.29