http://codeforces.com/gym/101933
F 빼고 다 풀었다. 풀이 보고 구현이라도 해보려고 했는데 기하에 4차 방정식 어쩌구 나와서 ㅋㅋㅋ...
NCPC는 문제가 참 재밌는 것 같다. http://koosaga.com/217 참고.
스포 방지선
________________________________________________________________________________________________________________________
________________________________________________________________________________________________________________________
B. Baby Bites & C. Code Cleanups & H. House Lawn
셋 다 깡구현인데, C가 조금 기분 나쁜 깡구현이다. 코드 짜면서 너무 헷갈림 ㅋㅋ
K. King's Colors
Vertex가 \(n\)개인 Tree를 \(k\)개의 색깔로 칠하는 방법의 수를 계산할 수 있다면, 포함-배제를 통하여 답을 빠르게 계산할 수 있다.
Root를 먼저 \(k\)개 색 중 하나로 칠하고, 트리를 내려가면서 색깔을 \(k-1\)개 중 하나로 계속 선택할 수 있다.
그러므로 \(n\)개인 Tree를 \(k\)개의 색깔로 칠하는 방법의 수는 \( k(k-1)^{n-1} \)이다. 시간복잡도는 \( \mathcal{O}(k \log n)\)
I. Intergalactic Bidding
'2배 이상' 조건 때문에 답이 존재한다면 유일하게 존재하고, greedy한 풀이를 적용할 수 있다. (cf. 2진법)
그래서 greedy하게 넣을 수 있는 가장 큰 값을 더해주면서 원하는 합을 만들 수 있는지 확인하면 된다.
숫자가 좀 많이 커서 big number를 써야한다. 복붙해서 적당히 비벼주면 AC.
J. Jumbled String
2년 전에 탈탈 털렸던 https://codeforces.com/contest/708/problem/B 문제와 정확히 동일하다.
\(a=0\)이나 \(d=0\)인 경우를 먼저 적당히 예외처리하고. 이제 \(a, d \neq 0\)인 경우만 고려하자.
\(cnt_0, cnt_1\)을 0과 1의 개수라 하면, \(a=\binom{cnt_0}{2}, d=\binom{cnt_1}{2}, b+c=cnt_0 \cdot cnt_1\)이 성립한다.
이를 통해 \(cnt_0, cnt_1\)의 값을 유일하게 결정할 수 있다. 또한, 위에 있는 \(a, b, c, d\)에 대한 식이 성립하면 string이 존재한다.
0이 \(cnt_0\)개, 1이 \(cnt_1\)개가 이 순서대로 나열된 string에서 시작해서, 1을 하나씩 왼쪽으로 보내자.
01을 10으로 swap하는 과정에서 b, c의 값은 정확히 1씩 변한다. 또한, 처음에 \(c=0\)이고 최종 상태에선 \(b=0\)이다.
게다가 \(b+c\)가 invariant이니 우리가 원하는 조건을 만족하는 string은 이 과정에서 만들어진다.
이 과정을 적당히 빠르게 simulate하거나 방정식을 풀어서 대강 \(\mathcal{O}(\sqrt{a+b+c+d})\) 풀이를 만들 수 있다.
E. Explosion Exploit
결국 중요한 것은 내 minion의 체력 집합/상대 minion의 체력 집합/남은 딜량이다.
생각보다 가능한 state가 몇 개 없음을 알 수 있고, 이를 통해서 동적 계획법을 세우면 된다.
초기 조건과 transition도 꽤 자명해서 풀이 자체는 쉽게 나온다. 나는 구현에서 좀 삽질했다.
처음에는 내 minion의 체력 집합/상대 minion의 체력 집합을 두 개의 vector로 관리했다.
즉, State를 vector 2개와 자연수 하나로 설정하여 관리했다.
vector를 항상 정렬된 상태로 만들고, vector 내부에 0이 없도록 관리하고, dp table을 map으로 만들었다.
map 내부에서 문제가 난 건지 단순 코딩 미스인건지는 잘 모르겠지만 코드가 잘 작동을 못했다.
그 다음에는 내 minion의 체력 집합/상대 minion의 체력 집합을 두 개의 string으로 관리했다. 여전히 망.
결국 내 minion의 체력 집합/상대 minion의 체력 집합을 두 개의 자연수로 관리했다.
체력 집합을 자연수 \( \sum_{i=1}^6 (\text{#number of minions with health }i) \cdot 10^{i-1} \)로 대응시켰다.
이제 State가 자연수 3개로 표현이 된다. 이제 답이 제대로 나오기 시작했는데, dp table을 map으로 관리하니 TLE가 떴다.
그래서 State를 큰 자연수 하나로 직접 hash해주고 (\(10^6\)진법), unordered_map을 사용했더니 AC. 힘들었다.
A. Altruistic Amphibians
코포에서 NCPC 2018 Open 글을 보면, 무게 합이 \(10^8\) 이하라는 조건을 보지 못했다며 댓글로 FUCK을 외치는 분이 있다.
이미 이 댓글을 본 상태여서 약간 스포일러 당한 상태로 문제를 풀었다. 풀이가 신기했다.
자기보다 가벼운 개구리만 지탱할 수 있으니, 항상 가벼운 개구리가 먼저 나간다고 볼 수 있다.
\( H_w\)를 \(w\)만큼의 무게를 지탱할 수 있는 개구리 탑의 높이의 최댓값이라 정의하자.
무거운 개구리부터 순서대로 보자. 시간 역순으로, 나중에 나갈 개구리부터 보자.
일단 \( H_{w_i} + Jump_i > D \)면 \(i\)번째 개구리가 탈출할 수 있다.
또한, \( H_w = \text{max}(H_w , h_i + H_{w+w_i}) \)로 (단, \(1 \le w \le w_i\)이다) 배열 \(H\)의 값이 update 된다.
결국 이 과정을 각 개구리에 대해 반복적으로 진행하면 된다. 시간복잡도는 \(\mathcal{O}(n \log n + \sum w_i )\)
D. Delievery Delays
재밌는 문제다. 일단 입력을 받고 다익스트라를 \(n\)번 돌려, 임의의 두 정점 사이의 최단거리를 구하자.
\( dist(i,j)\)를 \(i\)번째 주문이 들어온 지점과 \(j\)번째 주문이 들어온 지점 사이의 거리라 하자.
편의상 피자 가게는 \(0\)번째 주문이 들어온 지점이라고 하자.
Claim: \(K_n\)은 \(n\)이 홀수면 \(n\)개의 색으로, \(n\)이 짝수면 \(n-1\)개의 색으로 edge-colorable하다.
Proof of Claim: 사실 이게 tight한데, 증명은 자명하니까 넘어가자. construction만 찾아주면 된다.
Case 1. n 홀수: 각 정점에 \(0, 1, \cdots n-1\)을 두고, \(i+j \equiv k \pmod{n}\)이면 \(edge(i,j)\)를 색 \(k\)로 칠하자.
Case 2. n 짝수: proof without words. 한 1분 정도 그림 보고 있으면 바로 감이 잡힐 것이다. \(\blacksquare\)
이제 본 문제로 돌아와서, construction을 잡아보자. 각 사람을 (팀, 번호)로 표기하자. index는 적당한 mod를 취해서 보자.
\(n\)이 짝수인 경우에서는 먼저 \(K_n\)의 edge를 \(n-1\)개의 색깔로 칠하자. \(i\)번째 색깔로 칠해진 간선들을 \((u_{i,j}, v_{i,j})\)라 하자.
각 \(1 \le i \le n-1, 1 \le T \le m-1\)에 대해 다음을 반복한다.
각 \(1 \le k \le m\)에 대하여 \((k,u_{i,j})\)와 \((k+T,v_{i,j})\)가 경기하게 한다.
이를 하나의 round로 만들자. 총 \((n-1)(m-1)\)개의 round를 통해 '자신과 번호가 다른' 사람들과의 경기가 끝난다.
이제 \(K_m\)의 edge를 \(m\)개의 색깔로 칠하자. \(i\)번째 색깔로 칠해진 간선들을 \((u'_{i,j},v'_{i,j})\)라 하자.
각 \(1 \le i \le m\)에 대하여 다음을 반복한다.
각 \(1 \le k \le n\)에 대하여 \((u'_{i,j},k)\)와 \((v'_{i,j},k)\)가 경기하게 한다.
이를 하나의 round로 만들면, \(m\)개의 round를 추가하여 모든 시합이 끝나게 된다. 총 \((m-1)n+1\)개 round.
\(n\)이 홀수인 경우에서는 \(K_n\)의 edge를 \(n\)개의 색깔로 칠하자. \(i\)번째 색깔로 칠해진 간선들을 \((u_{i,j}, v_{i,j})\)라 하자.
또한, \(K_m\)의 edge를 \(m\)개의 색깔로 칠하자. \(i\)번째 색깔로 칠해진 간선들을 \((u'_{i,j},v'_{i,j})\)라 하자.
각 \(1 \le i \le n, 1 \le T \le m-1\)에 대해 다음을 반복한다.
각 \(1 \le k \le m\)에 대하여 \((k,u_{i,j})\)와 \((k+T,v_{i,j})\)가 경기하게 한다.
색깔 \(i\)를 가진 간선이 없는 유일한 정점 \(l_i\)를 잡자. \((u'_{T,j},l_i)\)와 \((v'_{T,j}, l_i)\)가 경기하게 한다.
이를 하나의 round로 만들자. 총 \(n(m-1)\)개의 round가 진행된다.
마지막 round에서 각 \(1 \le i \le n\)에 대하여 \((u'_{m,j},i)\)와 \((v'_{m,j},i)\)가 경기하게 한다.
총 \((m-1)n+1\)개의 round를 통해서 모든 시합이 끝나게 된다. AC. 코드는 좀 길다.
'PS > Problem Solving' 카테고리의 다른 글
Divide and Conquer Optimization (3) | 2019.04.07 |
---|---|
Convex Hull Trick과 Li-Chao Segment Tree (0) | 2019.04.04 |
Lazy Propagation (0) | 2019.04.02 |
Tishreen CPC 2017 (0) | 2018.10.04 |
BOJ #13407 Skinny Polygon (0) | 2018.10.02 |