2306] 유전자 BOJ 2016. 9. 25. 21:29

문제 설명

: 문자열 중에 길이 0 이상의 부분 문자열들을 제거해서 최대 길이의 KOI 유전자를 만드는 문제이다.
당연히도, 동적계획법 문제이다. 무엇을 제거하냐에 따라서 KOI 유전자가 달라지기 때문이다.

해결 방법은 두가지이다. 양끝이 a,t 이거나 g,c인 경우를 보거나, 인접한 a,t와 g,c를 보면 된다.

예를 들자면 aatt와 atat가 있다. 전자의 경우 안쪽에서부터 보면 되는 경우이고, 후자의 경우 바깥쪽에서부터
봐야하는 경우이다.

즉, dp(i,j) = 2 + dp(i-1,j-1)  ( 만약 a[i],a[j]가 각각 a,t이거나 g,c인 경우 )
그리고 양쪽에서 보지 않았을 경우 가능한 경우들을 모두 잘라내서 보는 후자의 경우 또한 봐주여야 한다.
dp(i,j) = max(dp(i,j), dp(i,k) + dp(k+1,j))  ( i<=k<j )



문제링크 [2306 : 유전자]



소스 코드


'BOJ' 카테고리의 다른 글

1301] 비즈공예  (0) 2016.11.12
1937] 욕심쟁이 판다  (0) 2016.10.14
8992] 집기 게임(Pickup Game)  (1) 2016.09.21
8462] 배열의 힘 & Mo's Algorithm  (0) 2016.08.20
1941] 소문난 칠공주  (0) 2016.08.14

문제 설명

: 어느 점에서라도 만나게 되는 무게 a인 가로선과 b인 세로선을 집어가면, a*b 만큼의 점수를 획득할 때,
최대로 한 쌍의 선들을 집어가면서, 점수를 크게하는 문제이다.


왼쪽에는 가로 선들의 집합을, 오른쪽에는 세로 선들의 집합인 이분 그래프를 형성 한 뒤,
MCMF 알고리즘을 이용해서 해결이 가능하다.

가로선은 x축에 평행하고 세로선은 y축에 평행하므로 선들이 만나는가에 대해서는 ccw까지 구현 할 필요가 없고,
간단하게 좌표 범위들로만 확인해서 연결 여부만 확인하면 된다.

MCMF 알고리즘 자체가 일단 최대로 유량을 흘려보내는 것이 목적이고, 그러면서 코스트는
최소화 하는 방향으로 작동하기 때문에 이 문제 조건에서는 코스트의 부호를 반대로 해주어서 가중치 그래프를 형성하면 우선순위로 최대로 유량을 흘려보내면서 두번째로 코스트 또한 큰 방향으로 구해낼 수 있다. (당연히 답을 도출 할 때에는 다시 부호를 바꾸어 주어야 한다.)


* 이 문제와는 관련이 없지만, 만약에 점수만을 최대화 하는 조건이라고 한다면 61번줄에 주석 친 부분을 사용하게 되는데, 이 경우에는 꼭 최대로 유량을 흘리지는 않지만,  코스트는 무조건 최대치까지 도달 할 수 있게된다.




문제링크 [8992 : Pickup Game]



소스 코드



'BOJ' 카테고리의 다른 글

1937] 욕심쟁이 판다  (0) 2016.10.14
2306] 유전자  (0) 2016.09.25
8462] 배열의 힘 & Mo's Algorithm  (0) 2016.08.20
1941] 소문난 칠공주  (0) 2016.08.14
1052] 물병  (0) 2016.07.22

문제 설명

: Description 그대로다. n개의 원소가 있고, [L,R]의 쿼리가 들어올 때마다
부분 배열의 힘을 구하는것이다.

여기서 라 하면 자연수 s의 개수를 뜻하는데, 부분 배열에서 이 모든 자연수 s에 대해** s
를 구하는 문제이다.



일단 당연한 것은 모든 Query에 대해서 다 훑어보는 식으론 절대 못푼다는 것이다. (의 시간 복잡도를 가지기 때문)



여기서 유용한 것이 Sqrt decomposition (평방분할)을 이용하는 것이다. 평방분할이라는 것은 간단하게 N개의 집합을 sqrt(N)개의 집합으로 나누어 값을 다룬다고 생각하면 되는데,이 문제에서는 Query에 이것을 적용하는 Query Sqrt Decomposition을 이용할 것이다.

query에 대해서 분할하는 것을 Mo's Algorithm이라고도 하는 것 같은데 각각의 query [L,R] 에 대해서 L/sqrt(N)으로 정렬을 한다. (같을 경우 R에 대해서 정렬, 다르게 보자면, (L/sqrt(N))*sqrt(N) + R/sqrt(N) 이라는 value로 오름차순 정렬을 한다고 보면 된다.)

물론, 정렬을 하게 되면 query의 순서가 뒤바뀌기 때문에 따로 index를 저장 해주어야 하고,값을 변경하는 query가 존재하는 경우 적용 할 수 없는 것 같다. 
대신, 구간의 특정 수의 개수라던가 하는 특수한 형태의 문제에는 아주 잘 적용되는 것 같다.


결론적으로,  N개의 원소가 존재하고 query [L,R]이 존재할때, L/sqrt(N)과 R 우선순위로 정렬을 하게 된다면

1. N/sqrt(N) = sqrt(N)개의 집합(이제 Block이라고 하겠다)이 형성된다.

2. 하나의 Block 내에서 query [L,R] -> [L',R']의 변화가 있다고 하면, L'-L <= sqrt(N) 이고 R<=R' 이다. (즉, 같은 Block에서의 L/sqrt(N) 값은 동일하다)

3. 동일 Block 내에서의 R의 변화는 최대 N까지이므로, 최종적으로 모든 query에서의 R은 
시간 복잡도 내에 변화한다.

4. 한 Block 내에서의 L의 range는 sqrt(N)이므로 (L/sqrt(N) 에 대해서 정렬을 해서 집합으로 묶어놨으니 당연한 것이다) 최종적으로 모든 query에 대해서 L은 시간 복잡도 내에서 변화한다.

5. 그렇기 때문에 Mo's algorithm은 의 시간 복잡도를 갖는다. (F는 L,R의 변화 할 때마다 값을 처리해주는 함수를 만들었을때, 그 함수의 처리 시간이다.)


그렇기 때문에 구간의 합 구하기, 최대값 구하기 같은 유형의 문제들을 굳이 segment tree나 fenwick tree를 구현하지 않더라도 최초의 [L,R]을 설정해 놓고 정렬된 query를 쭉 훑으면서 [L,R] -> [L',R']로의 query range를 확장, 축소 해나가면 해결이 가능하다.


더 자세한 내용은 링크를 통해 보는 게 좋겠다.

http://www.geeksforgeeks.org/mos-algorithm-query-square-root-decomposition-set-1-introduction/

https://www.hackerearth.com/notes/mos-algorithm/



문제링크 [8462 : 배열의 힘]



소스 코드



'BOJ' 카테고리의 다른 글

2306] 유전자  (0) 2016.09.25
8992] 집기 게임(Pickup Game)  (1) 2016.09.21
1941] 소문난 칠공주  (0) 2016.08.14
1052] 물병  (0) 2016.07.22
1328] 고층 빌딩 , 8895] 막대 배치  (0) 2016.05.07