2018. 1. 6. 22:51ㆍ알고리즘 문풀/Others
Lobelia, RickMcCoy 와 함께 연습한 대회다. (팀명 : Red Lung)
나는 C를 잡았는데, 결과는 1 solve로 초라했지만 대회가 끝나고 1시간 가량 더 잡아서 풀어냈다.
(애초에 QR을 치려고 했는데 내가 예약을 FR로 잘못한 걸 나중에서야 알았다...)
장의 서로 다른 카드에 숫자 이 적혀 있다. () 이 카드들을 적당히 한 줄로 길게 이어붙여 만든 큰 숫자가 의 배수가 되는 경우의 수를 로 나눈 나머지를 구하여라.
Tag : Combinatorics, Dynamic Programming, FFT, DP optimization with FFT
Step 0. Initialization
11의 배수판정법을 이용하면, 에서 중요한 것은 로 나눈 나머지와 자릿수의 기우성 뿐임을 알 수 있다.
전체 수의 나머지에 대해,
어떤 수 의 오른쪽 (낮은 자리)에 있는 수들의 개수가 홀수인 수는 만큼,
오른쪽의 수 개수가 짝수인 수는 만큼 기여할 것이다. (뭐라는거야...)
즉, 수를 이어붙이다가 자릿수가 홀수인 숫자가 나올 때마다, 나머지에 기여하는 "부호가 바뀐다".
따라서 들을 2개의 vector에다가 자릿수의 기우성에 따라 분류하여 넣는데, 을 벡터에 넣는다.
Step 1. 홀수 자릿수인 수들의 순열 개수 구하기
애초에 이 문제는 가능한 '순열'의 수를 구하는 문제이기 때문에 재귀적인 DP로는 잘 풀리지 않는다.
즉, 가능한 '조합'의 수를 구한 뒤 거기에 팩토리얼을 곱하는 유형일 가능성이 높다.
홀수 자릿수인 수들을 11로 나눈 나머지를 각각 라고 하자.
이들을 일렬로 순서대로 배열한 것을 오른쪽부터 라 두면
는 부호가 바뀌어서, 은 부호가 그대로 들어갈 것이다.
즉, 에 임의로 부호를 부여했을 때, 음수를 부여받은 숫자가 정확히 개인 조합의 수에 를 곱한 것이 홀수 자릿수 순열의 가능한 배열 개수가 된다.
조합의 수는 생성함수를 이용하여 구할 수 있는데, 먼저 인 변수 를 잡자.
여기서 는 복소수가 아니고, 그래서 이다.일종의 벡터 를 다항식의 form 로 생각하기 위해 도입한 변수이다.
이라고 하면
이다. 이는 다항식의 곱과 매우 흡사한 form임을 알 수 있고,
이것이 의 직관적인 정의가 수학적으로 해괴하게 기술되는 이유이다.
각각의 를 로 대응시킨 1차 다항식 개를 모두 곱하는 것이다.
이 과정은 FFT와 분할 정복을 이용하여 에 수행될 수 있으며, 가 좋으니 정수 FFT를 사용할 수 있다.
(원시근은 )
이 차 다항식에서 의 계수가,
개의 숫자에 음수를 부여해서 적당히 합쳤더니 로 가 되는 조합의 수가 된다.
이 벡터를 이라고 하자.
Exception 1.1. 인 경우
이 경우는 모든 수의 자릿수가 짝수이므로 답은 또는 이다. 을 다 더해서 0인지 체크해주면 된다.
Exception 1.2. 인 경우
이 경우는 짝수 자릿수인 수가 존재하지 않으므로, 에서 의 계수가 답이 된다.
아래는 인 경우를 생각한다.
Step 2. 짝수 자릿수인 수들의 순열 개수 구하기
이 경우는 조금 더 복잡하다.
똑같은 풀이를 쓰는데 원하는 답은 다르다.
수학적인 상황으로는 홀수들을 '칸막이'로 생각하고,
음수를 부여받은 수들을 번째 칸막이와 번째 칸막이 사이에,
양수를 부여받은 수들을 번째 칸막이와 번째 칸막이 사이에 배치하도록 하는 경우의 수이다.
우선 를 의 계수 이라고 생각하자.
짝수 자릿수 수들을 11로 나눈 나머지를 라고 하자. ()
이번에도 똑같이 를 다 곱한다.
동자순열(같은 것이 있는 순열)을 이용해서 머리를 잘 굴리면,
에서 의 계수가 짝수를 잘 배치했을 때 로 가 나오게 할 수 있는 순열의 수임을 알 수 있다.
따라서 위 식의 벡터를 라고 하자.
Step 3. 답 구하기
의 계수가 답이 된다. 저 곱하기는 당연히 외적이 아니라 위에 정의된 벡터곱이다. 풀이 끝!
Complexity :
FFT를 사용하지 않는 DP 풀이가 있는데, 나의 FFT 구현이 상당히 느림에도 불구하고 내 코드가 3배 이상 빠르다.
'알고리즘 문풀 > Others' 카테고리의 다른 글
JOI 2012 final round #5 - JOI 국가의 행사 (2) | 2018.07.21 |
---|---|
요리 강좌 - KOI 2017 고등부 #3 (3) | 2018.01.24 |
Codeforces Goodbye 2017 Contest (0) | 2017.12.30 |
Codechef 2017 November LunchTime (0) | 2017.11.26 |
CodeForces #447 (Div.2 Only) (1) | 2017.11.20 |