티스토리 뷰

APIO

APIO 2016

arnold518 2019. 9. 13. 02:00

http://apio-olympiad.org/2016/

https://oj.uz/problems/source/184

https://koosaga.com/113


3. Gap


Subtask 1


한번에 양 끝의 값 2개씩 알아간다고 생각하자. 지금 아는 끝값으로 쿼리를 날리면 그 다음 끝값 2개를 알 수 있다. 사용하는 쿼리의 개수는 ceil(N/2) 개로, 30점을 받 수 있다.


Subtask 2


Subtask 2에서는 쿼리의 개수만 중요한 것이 아니라, 한 쿼리가 적은 수들을 덮고 있어야 한다.


만점을 얻기 위해서는 한가지 중요한 관찰이 필요하다.

일단 첫번째 쿼리로 최소값과 최대값 s, e를 구했다고 생각하자.


[s, e] 구간 안에 gap들은 N-1개가 있으니, max gap < (e-s)/(N-1) 의 상황이 가능할까?

max gap < (e-s)/(N-1) 이니, sum gap = e-s < (e-s)/(N-1)*(N-1) = e-s 로 모순이다.

즉, max gap >= (e-s)/(N-1) 이니, (e-s)/(N-1)를 사이즈로 하는 버킷으로 전체 [s, e]구간을 커팅해주면 한 버킷 안에 max gap 은 존재할 수 없다. 이제, 각 버킷에 대해서 쿼리를 날리고, 버킷의 양 끝값을 알고 있으면 된다.


사용하는 쿼리의 개수는 처음에 1개 + 버킷 N-1개 / 쿼리가 덮는 수들의 수는 처음에 N개, 버킷의 합이 N개로, 총합 3N개 만점을 받을 수 있다.


N=2일때는 특히 예외처리를 해 주어야 한다.



1. Boat


이 문제는 DP로 해결된다. (+조합)


가장 중요한 것은 각 보트마다 어떤 구간에 속하는지를 선택해놓으면 경우의 수가 정해진다.


일단 첫번째로, [Ai, Bi]를 [Ai, Bi+1) 꼴로 바꾼 다음, 모든 값들을 좌표압축하여 구간 2N개로 쪼갠다.

따라서 DP를 다음과 같이 정의하자. 

DP[i][a] = i번 보트를 0개 초과 내보내고, 그 개수가 구간 a에 포함될 때의 경우의 수

이제 열심히 상태 전이 식을 세워보자.




지금 (i, a) 를 선택했으니, 전 선택이 a인 경우는 따로 처리하고 (i-1, a-1) 일 때를 생각하자.

i바로 전에 선택한 보트가 j라 하면 dp(i, a) = sum(dp(j, 1~a-1))*C 가 된다.

이때 C는 j+1~i번째의 보트들이 선택이 되지 않거나, 선택되면 a구간의 수들일 때이다.


만약 여기서 k개의 보트들이 선택되는 보트이고, p는 j+1~i 에서 구간 a를 포함하는 보트들의 수라 하자.

x개를 선택하고 싶다면 경우의 수는 p-1Cx-1*aCx (i번째 보트는 무조건 선택해야 하기 때문) 이다.

즉, f[x]=sum(x-1Ci-1*aCi-1) 꼴로 표현될 수 있다.


지금 구해야 하는 값들은 a<=b<=500 의 aCb와 정해진 a<=10^9 , b<=500 의 aCb이다. 첫번째 값들은 N^2 전처리를 통해 구할 수 있고, 뒤의 값은 mod inv 를 모두 구해논 뒤, N/1, N/1 * (N-1)/2, N/1 * (N-1)/2 * (N-2)/3 처럼 식을 통해서 계산할 수 있다. 이를 효율적으로 하기 위해서는 구간의 길이 a가 정해져야 하기 때문에, 2차원 dp배열을 한 세로줄씩 구해가면 된다.


첫번째 줄은 예외 처리를 잘 해주어야 한다.


시간 복잡도 : O(N^3)



2. Fireworks


일단 Subtask 2를 tree dp를 이용하여 해결할 수 있다. 

'APIO' 카테고리의 다른 글

APIO 2019  (0) 2019.12.27
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함