출처 : https://www.acmicpc.net/problem/9935

정답 : https://github.com/stemp12/study/blob/master/acmicpc.net/2016.08/9935.cpp


이 문제는 참 좋은 문제였다. 얼핏보면 매우 간단한 문제로 보였다. 그러나 자꾸 시간초과가 났고, 결국 문자열길이가 최대 백만이라는 점이 문제가 되고 있음 을 깨달았다.

초기 알고리즘은 폭발문자열을 찾고 그부분을 지우고 다시 찾고 지우고 이런식으로 진행했다. 생각해보니 찾는다는것 자체가 백만이라는 가정하에 너무도 늦게 찾을것 같았다.

그래서 생각한것이 스택처럼 다루는 것이다. 문자열을 하나씩 추가하고 끝문자를 기준으로하여 만약 폭발문자의 끝문자와 현재 스택으로쓰는 스트링의 끝문자가 같다면 폭발문자열과 같은지 그때만 비교를 하는것이다. 같다면 인덱스값을 조절하여 다시 저장하게 하는 방식으로 진행하였는데, 이렇게하니 상당히 빠른 속도를 보이며 정답을 맞았다.


이 키워드를 얻은 계기는 폭발문자열이 최대 40문자가 안된다는 점이었다. 그렇다면 폭발문자열만 자주 사용해주어도 되겠다고 생각하여 진행하였다.


참 괜찮은 문제라고 생각한다.

'Algorithm' 카테고리의 다른 글

[AC] 11057 오르막 수  (0) 2016.08.03
[AC] 1967 트리의 지름  (0) 2016.08.03
[AC] 1613 역사  (1) 2016.08.03
[AC] 1298 노트북의 주인을 찾아서  (0) 2016.08.03
[AC] 1005 ACM Craft  (0) 2016.07.26

출처 : https://www.acmicpc.net/problem/6549

정답 : https://github.com/stemp12/study/blob/master/acmicpc.net/2016.07/6549.cpp


이 문제는 상당히 애를 먹었고 시간을 엄청 쏟아부었다. 

정말 쉽지 않은 문제였다. 처음에는 세그먼트트리로 접근을 하였으나 도무지 답에 근접할수가없었고, 시간상 무조건 TL이 나오는 설계만 나왔다. 시간을 더줄이기위한 풀이법을 생각하다가 이렇게도 저렇게도 안되어 고민하고있던차에 문제분류를 보니 스택도 가능하다고 하여 스택을 생각해봤다.

만약 이 문제를 스택으로 푼다면..스택에는 어떤데이터가 들어가야할까? 

높이 혹은 해당인덱스가 들어가야할것 같았다. 그리고 생각한게 어떤 규칙을 사용하여 스택에 넣을것인가?

점점 줄어들게 넣을것인가? 점점 증가되게 넣을것인가? 여기서 계속 생각하다가 점점 줄어들게 스택을 구성하면 예제도 풀기 어려워 반대로 생각하였다. 

점점 증가하도록 구성하고 만약 인풋이 작다면 새로 넣어주기 전에 넓이를 계산하게 하였다. 여기서 다시 엄청난 시간을 소모하였다. 어떻게 넓이를 구할것인가? 예제는 구했으나 수차례 오답을 맞았고 특이 케이스를 찾아냈다. 

만약 인풋이

7 101 321 128 50 68 99 100

라면 정답은 50을 기준으로 전부 계산한 350이 나와야 한다. 그러나 내가만든 풀이는 좀처럼 이 케이스를 계산하지 못하였다.

그리고 구한 풀이는 다음과 같다.

1. 스택이 비어있거나 스택의 탑보다 현재 인풋이 크다면 그냥 스택에 푸시한다.
2. 1번에서 그렇지 않다면 스택을 비우면서 계산을 한다. 계산은 다음과 같이 진행한다.

1) 먼저 스택의 탑보다 현재 입력이 커지면 스택을 그만 비우고 종료를 한다.
2) 그 경우가 아니라면 top을 현재의 스택탑으로 만들고 하나를 제거한다.
3) 다시 새로운 찹을 left에 담아둔다. 즉 현재최고막대기에서 그 바로다음막대기에 해당한다. 
4) 하지만 스택이 비어있다면 left를 -1로 값을 만든다.
5) 넓이를 구하는데 넓이는 현재 최고 막대기길이*(현재 인덱스 - left -1)을 해준다. 왜 이렇게 구성이되냐면 만약 예제처럼 4 5 1이 들어왔을때 일단 4 5 가 스택에 있을텐데 현재인덱스(4)-left(4가 위치한 인덱스인 2)-1 or (left+1) 을 하면 현재 5가 가진 최고 넓이가 나오고 다시 이제 왼쪽으로가면 현재인덱스 4에서 1이 위치한 1번으로오고 다시 그 직전까지의 넓이를 계산하여 최대값을 갱신하는 방식이다. 

3. 위 과정으로 스택을 점점 증가하도록 구성하는데 입력이 종료되면 이제 스택을 끝까지 비우면서 위과정을 실행한다. 그런데 여기서 만약 스택이 완전히 비어진다면 즉, 완전히 비어지기전 녀석은 현재 인풋중 가장 작은녀석을 의미하는데 이녀석은 전체 길이만큼 곱해주면 되는 특별한 경우가 된다. 

여기서 나는 만약 내가 만든 인풋에서 68이 51이면 값이 변할수있지 않을까 생각했는데 그렇다면 결국 50이라는 값을 버리게 되므로 값이 작아지고 68이라고해도 전수가 만약 1인 경우도 생각해봤는데 이때는 앞에서 계산한 맥스값은 321이 되고 현재 스택에는 1 68 99 100 이 있는데 68일때는 1때문에 완전 분할되버리기때문에 불가하다. 

암튼 문제를 이해하면서 자가당착에 빠져 조금 혼란스러웠지만 결국 풀어내긴하였다. 상당히 애먹은 문제이다.


'Algorithm' 카테고리의 다른 글

[AC] 1298 노트북의 주인을 찾아서  (0) 2016.08.03
[AC] 1005 ACM Craft  (0) 2016.07.26
[AC] 1021 회전하는 큐  (0) 2016.07.25
[AC] 1780 종이의 개수  (0) 2016.07.25
[AC] 2636 치즈  (0) 2016.07.18

출처 : https://www.acmicpc.net/problem/1874

해답 : https://github.com/stemp12/study/blob/master/acmicpc.net/2016.01/1874.cpp


예전부터 풀어야지 하며 안풀었던 문제를 드디어 풀었다. 엄청 간단할줄 알았는데 생각외로 해맸다. 졸려서 그런거 같다.

이 문제는 이름만 봐도 스택을 써야할듯한 문제이다. 내용도 스택을 쓰세요~~ 라고 말하는것 같다. 하지만 경험상 스택문제의 경우 거의 대다수는 스택이 필요없고 배열로만 할 수 있으며, 훨씬 속도면에서 빠르다. 구현도 훨씬 쉽다. 그러나 큐나 리스트같은경우는 배열로는 답이 나오지 않는 경우가 대다수이다.

이 문제에 먼저 기억해야할 점은 불가능한경우 NO를 출력하라고 한 점이다. 불가능할 경우가 있다는 말이니 예외처리를 해줘야한다. 나는 역시 이부분을 놓쳤다가 나중에서야 다시봤다. 하지만 이번엔 빨리 캐치해냈다.

풀이를 살펴보면 다음과 같다.

1. 입력을 받아 스택의 최상단 값과 비교를 한다.

2. 입력값이 최상단 값보다 크다면 현재 사용된 가장 큰 수부터 입력값까지 스택에 새로이 쌓는다.

3. 그 후에 최상단 값과 입력값을 비교한다.

4. 일치하면 최상단 스택을 지워버리고, 일치하지 않는다면 불가능한 경우다.


여기서 설명을 덧붙이자면 스택에는 현재 숫자의 입력에 따라 순차적으로 쌓여있다. 그런데 입력값이 스택의 최상단 값과 일치하지 않는다는 말은 스택의 순서를 무시한 경우이거나, 이미 사용된 수이거나, 전혀 관련없는 수일가능성이 높다. 그렇기 때문에 불가능한 경우가 된다. 이해가 되지 않는다면 역시 손으로 써보면서 증명해보는게 최고다. 그리 어렵지 않은 문제였다.

'Algorithm' 카테고리의 다른 글

[AC] 1931 회의실배정  (0) 2016.01.26
[AC] 2304 창고 다각형  (0) 2016.01.26
[AC] 7568 덩치  (0) 2016.01.23
[AC] 1629 곱셈  (0) 2016.01.22
[AC] 9471 피사노 주기  (0) 2016.01.22

+ Recent posts