PS 재활의 필요성을 체감했습니다. KOI 2차를 매우 심하게 망쳤기 때문입니다. 3달 정도 PS를 안 했더니, 골드 중위 문제도 못 푸는 수준의 실력이 되었더라고요. 문제는 AtCoder에서 찾아 풀기로 했습니다. 문제 양도 상당하고, 전형적인 테크닉을 많이 배울 수 있으며, 무엇보다 모든 문제의 풀이가 공개되어 있기 때문입니다. 여름방학 동안 푼 AtCoder 문제들을 정리해 보았습니다. 괄호 안의 수는 Kenkoooo에서 볼 수 있는 난이도입니다.
수열 내에서 약수가 자신뿐인 수의 개수를 구하는 문제입니다. 에 중복 원소가 있다면 서로가 서로의 약수가 되므로 중복 원소를 모두 배제합니다. 그 다음 각 에 대해 을 만족하는 를 모두 찾습니다. 찾은 들은 답의 개수에 포함될 수 없습니다. 이 작업을 모든 에 대해 반복해 주면 됩니다. 의 중복이 없고 그 최댓값 이므로, 조화수열의 합에 의해 시간 복잡도는 이 됩니다.
때문에 귀찮아 보이지만, 사실 , , ..., 에서 뽑은 수의 개수와 합 쌍이 몇 종류인지 묻는 문제와 같습니다. 개의 수를 뽑는다고 할 때 가능한 최솟값과 최댓값은 에 쉽게 구할 수 있고, 이들 사이의 수를 모두 만들 수 있음 또한 자명합니다. 이것을 이상 이하의 모든 에 대해 실행하면 에 문제를 해결할 수 있습니다. 더욱 최적화하면 전체 문제를 에도 해결할 수 있지만, 의 범위가 그렇게까지 크지 않으므로 필요는 없습니다.
개의 점 중 맨해튼 거리가 가장 긴 두 점 사이의 맨해튼 거리를 구하는 문제입니다. 일반성을 잃지 않고 일 때, 맨해튼 거리는 입니다. 따라서 각 점에 대해 x좌표와 y좌표의 합과 차를 각각 저장해 주고, 합의 최댓값과 최솟값 차이 , 차의 최댓값과 최솟값 차이 중 더 큰 것을 출력하면 됩니다.
중복조합 의 값은 입니다. 따라서 가능한 모든 수열 를 한 번씩 조사해 볼 수 있습니다. 모든 에 대해 점수를 계산하고 최댓값을 출력하면, 의 시간 복잡도에 문제를 해결할 수 있습니다.
파란 공을 모으기 위해 번의 시행이 필요하다는 것은 연속된 파란 공의 묶음이 개라는 것과 같습니다. 따라서 파란 공을 개의 묶음으로 나눈 뒤 다음 중 하나를 선택하면 됩니다.
따라서 경우의 수는 가 됩니다. 과 가 각각 최대 이므로, 에 조합을 구하는 DP를 이용하여 쉽게 해결할 수 있습니다. 일 때의 예외 처리에만 신경 쓰면서 풀어 줍시다.
주어진 식 그대로 계산하면 됩니다. 부동소수점 오차가 없도록 실수 나눗셈 대신 정수 곱셈을 활용해 줍시다.
가 keep일 때만 를 결과에 더하여 출력하면 됩니다.
, , , ..., 로 이루어진 정수를 라고 합시다. 인덱스는 1-based입니다. 그러면 모든 식에서 가 등장하는 횟수는 입니다. 따라서 가 문제의 답이 됩니다.
2차원 배열 를 만들고, 각 쿼리마다 대입을 합니다. 이제 오른쪽 아래에서 왼쪽 위로 가는 누적 max를 적용해 주면, 각 칸에 적용되는 마지막 쿼리의 번호를 알 수 있습니다. 번호에 맞추어 문자를 출력해 줍시다. 시간 복잡도는 입니다.
부터 까지의 정수가 하나씩 저장된 두 배열 , 를 만듭니다. 는 각 원소 에 대해 가 큰 것부터 순서대로 정렬되어 있습니다. 는 각 원소 에 대해 가 큰 것부터 순서대로 정렬되어 있습니다. 이제 주어진 분할 방식에 의해 다음 중 적어도 하나가 성립합니다.
전자가 참이라면 부터, 후자가 참이라면 부터 탐색을 진행합니다. 여기에서는 전자가 참이라고 가정합시다. 그러면 가 성립하는 가장 큰 까지 왼쪽부터 차례대로 놓습니다. 남은 열의 개수는 입니다. 그러면 로 탐색 대상을 바꾸어, 이 성립하는 가장 큰 까지 위부터 차례대로 놓습니다. 물론 이전에 이미 놓은 조각은 우선적으로 지나칩니다. 남은 행의 개수는 입니다. 로 탐색 대상을 다시 바꿉니다. 이러한 작업을 모든 조각을 사용할 때까지 진행하면, 전처리를 제외하고 시간 복잡도 에 문제를 해결할 수 있습니다. 전처리를 포함하면 입니다.
길이가 인 부분 수열에 대해, 그 평균은 합을 로 나눈 것입니다. 따라서 길이가 인 모든 부분 수열에 대해 그 합의 총합을 먼저 구해 봅시다. 길이가 일 때 을 정의합니다. 그러면 각 가 총합에 등장하는 횟수는 입니다. 누적 합을 잘 이용하면 모든 에 대한 부분 수열의 합의 총합 을 에 구할 수 있습니다. 따라서 구하는 값은 이고, 각 마다 모듈러 곱셈 역원을 취해 더해 주면 됩니다.
이동을 번, 이동을 번 해야 한다고 하면, , 입니다. 이때 와 중 정수가 아니거나 보다 작은 것이 있다면 답은 , 그렇지 않으면 답은 입니다.
ARC100의 첫 번째 문제와 같은 문제입니다.
를 정의합시다. 그러면 구하는 값은 의 최솟값이고, 이것을 최소로 하는 정수 는 수열 의 중앙값임이 잘 알려져 있습니다. 따라서 를 그 값으로 놓고 계산해 주면 됩니다. 시간 복잡도는 중앙값 계산을 위해 정렬을 수행하므로 입니다.
를 으로 바꾼다면, 이것은 를 제거하는 것과 동일합니다. 따라서 원소 하나를 제거했을 때 GCD의 최댓값을 구하면 됩니다. 이는 양쪽 방향에서 누적 GCD를 계산하는 방법으로 쉽게 구할 수 있습니다. 시간 복잡도는 입니다.
ARC084의 첫 번째 문제와 같은 문제입니다.
먼저 각 부분을 크기 순으로 정렬하여 순서를 다시 매깁니다. 이제 상부를 고려하지 않고, 중부와 하부만으로 제단을 만들 수 있다고 합시다. 이때 각 중부에 대하여 만들 수 있는 제단의 수는 이분 탐색으로 쉽게 알 수 있습니다. 번째 중부와 임의의 하부로 만들 수 있는 제단의 수를 라고 합시다.
이제 번째 상부보다 큰 최소 번호의 중부를 번째 중부라고 합시다. 그러면 번째 상부로 만들 수 있는 제단의 수는 입니다. 이 값은 역방향 누적 합으로 쉽게 구할 수 있으므로, 그 합을 구해주면 시간 복잡도 으로 전체 문제를 해결할 수 있습니다.
ARC062의 두 번째 문제와 같은 문제입니다.
아래 제시한 문제는 원래 문제와 동치입니다.
g일 경우 , p일 경우 입니다.g나 p를 선택할 수 있습니다. g를 선택하면 부여된 점수에서 을 뺀 점수를 얻고, p를 선택하면 부여된 점수를 그대로 얻습니다.g를 선택한 횟수는 p를 선택한 횟수 이상이다.g는 적어도 번 선택해야 하므로, 부여된 점수의 합에서 이 값을 빼면 정답이 됩니다. 시간 복잡도는 입니다.
ARC064의 첫 번째 문제와 같은 문제입니다.
라면 을 까지 줄여 주어야 함은 자명합니다. 이제 그 다음을 봅시다. 를 이하로 줄이기 위해서는 을 줄이거나 를 줄일 수 있습니다. 그런데 를 줄이면 도 함께 줄어들기 때문에 를 줄이는 것이 반드시 더 유리합니다. 이를 까지 반복해 주면 시간 복잡도 에 전체 문제를 해결할 수 있습니다.
이므로, 브루트 포스가 충분히 가능합니다. 완전 그래프에서 가능한 경로는 개인데, 이 개의 경로를 전부 확인하면서 거치는 모든 간선이 주어진 그래프에 있는지 확인하면 됩니다. 시간복잡도는 입니다.