[추석맞이 폴란드 스터디] 180924

2018. 9. 25. 00:38알고리즘 문풀/Others

겨우겨우 두 문제를 풀어냈다. 진도 따라잡기도 벅찰 거 왜 한다고 해서...


오늘 푼 문제들 (2 / Total 10)


POI96. Knights  (Div1A)

POI98. One-sequences (Div1A)


고민중인 문제들


POI96. Castle

POI04. 스타 대회



Spoiler Alert.

This section is intentionally left blank.




















POI96. Knights

Tag : DP, Bitmask


Description에 심각한 오류가 있다. 문제에서 주어지는 set Z는 나이트가 있어야 할 곳이 아니라 있으면 안되는 곳이다. 현재 ko_osaga님이 지적해둔 상태.


보드의 세로가 3밖에 안되기 때문에 자연스럽게 3 * n DP를 생각해볼 수 있다.

하지만 체스보드에 놓여 있는 것이 "나이트"라는 공식화하기 어려운 대상이기 때문에, 결국 (i-1)열까지 위치한 나이트의 정보를 전부 들고 다녀야 한다는 생각이 든다. 당연히 이건 시간, 메모리 모두 만족시키지 못하고...

나이트가 행, 열 중 한 방향으로 이동할 수 있는 최대 길이는 2. 따라서 i열에 나이트를 배치하는 문제에서 (i-2)열보다 왼쪽에 위치한 나이트는 아무 의미가 없다. 따라서 이전 6개 나이트의 정보만 들고 다니면 i열의 나이트 배치 문제를 해결하기에 충분하다.


D(i, k, b) := i열까지, 총 k개의 나이트를 배치하는 경우의 수, 이 때 이전 6개의 나이트의 상태(bit - string)은 b이다.


코딩이 꽤 까다로운 편이다. Z의 원소에 의해 나이트를 놓을 수 없는 칸, 기존의 나이트에 의해 나이트를 놓을 수 없게 되는 칸을 모두 고려해야 한다. i열에 놓고 싶은 나이트의 상태를 X라는 3비트 정수로 나타내고 작두를 타며 비트마스킹을 해야 한다. 이 이상의 디테일은 혼자 생각하는 편이 더 간단할 것 같다.


나이트를 최대 3n3n개밖에 놓을 수 없으므로, 시간 복잡도는 O(n * 3n * 8 * 64) ~ O(1536n2)O(1536n^2)이 된다. n = 100을 대입하면 연산량이 10^7에 육박함에도 불구하고 커팅이 잘 되는지 4ms가 나왔다.


jh05013님의 블로그O(512n)O(512n) 정도로 보이는 솔루션이 있다.


왜인지 모르겠지만 경우의 수는 long long으로 충분하고, 토글링을 이용하면 메모리를 줄일 수 있다.

09.25) 크리님이 SA로 답이 101510^{15}까지 나오는 데이터를 만드셨다. 조만간 롱롱 뚝배기가 터질 것 같다...


POI98. One-sequence

Tag : Observation, Parity


a1=0,aiai+1=1a_{1} = 0, |a_{i}-a_{i+1}| = 1인 수열의 길이가 nn, 합이 SS가 되게 a를 만들어야 하는 문제이다.

문제 자체는 간단한 기우성 관찰로 풀 수 있지만, 문제를 봤을 때 빠르게 이 관찰을 떠올리기까지는 수련이 필요할 것 같다.


우선, 절댓값이 n(n1)2\frac{n(n-1)}{2}보다 큰 수는 만들 수 없음이 명백하다.

그리고 SSn(n1)2\frac{n(n-1)}{2}의 기우성이 다른 경우에도 만들 수 없다. 알아내는 방법은 여러 가지가 있겠지만, 다음의 argument가 깔끔하다.


a1=00(mod2)a2a11(mod2)aiai11(mod2)aii1(mod2), a1++aii(i1)2(mod2) a_{1} = 0 \equiv 0 (\text{mod} 2) \\ a_{2} - a_{1} \equiv 1 (\text{mod} 2) \\ \vdots \\ a_{i} - a_{i-1} \equiv 1 (\text{mod} 2) \\ \therefore a_{i} \equiv i-1 (\text{mod} 2), \ a_{1} + \cdots + a_{i} \equiv \frac{i(i-1)}{2} (\text{mod} 2)


나머지 경우, 즉 S의 절댓값이 n(n1)2\frac{n(n-1)}{2} 이하이면서 기우성도 맞아 떨어지는 경우에는 전부 만들 수 있을까? 놀랍게도 정말 만들 수 있다. 실제로 a를 construct하는 방법은 편의에 따라 다를 수 있는데, 내 기본 아이디어는 수열의 합을 n(n1)2\frac{n(n-1)}{2}에서 2씩 떨굴 수 있다는 것이다.


bi=ai+1aib_{i} = a_{i+1} - a_{i}라고 하고, bi=1b_{i} = 1인 0 < i < n을 '증가점', bi=1b_{i} = -1인 i를 '감소점'이라고 하자.

초기에는 모든 i가 증가점이고, 합은 n(n1)2\frac{n(n-1)}{2}가 된다.

이 때 k < n이 감소점이 되는 경우, 수열의 합이 정확히 2(n-k)만큼 감소하게 된다.

만약 Sn(n1)22(n1)S \ge \frac{n(n-1)}{2} - 2(n-1)인 경우는 종료. 아니라면 1을 감소점으로 설정한 뒤, b[2..n]에 대해서 동일한 문제를 풀면 된다.


구현은 놀랍도록 간단하지만, 나는 이걸 폰코딩으로 풀다가 4번이나 틀려버렸다.