알고리즘

[Swift 알고리즘] 백준_22862 가장 긴 짝수 연속한 부분 수열

마라민초닭발로제 2024. 3. 29. 14:08

 

문제

n개의 정수로 이루어진 수열이 있다. 이 수열에서 한 정수를 제거하거나, 또는 두 정수를 제거할 수 있다. 한 정수를 제거하는 경우에는 그 정수가 점수가 되고, 두 정수를 제거하는 경우에는 두 정수의 곱이 점수가 된다. 이를 반복하여 수열에 아무 수도 남지 않게 되었을 때, 점수의 총 합의 최대를 구하는 프로그램을 작성하시오.

예를 들어 -1, 5, -3, 5, 1과 같은 수열이 있다고 하자. 먼저 1을 제거하고, 다음으로는 5와 5를 제거하고, 다음에는 -1과 -3을 제거했다고 하자. 이 경우 각각 점수가 1, 25, 3이 되어 총 합이 29가 된다.

입력

첫째 줄에 정수 n(1 ≤ n ≤ 100,000)이 주어진다. 다음 n개의 줄에는 절댓값이 1,000,000을 넘지 않는 정수가 n개 주어진다.

출력

첫째 줄에 최대 점수를 출력한다.

 

 

해결 방법

- 슬라이딩 윈도우

-투포인터

- 그리디

 

수열을 만듦에 있어서 중요한건 현재 오른쪽 포인터가 최대 왼쪽 포인터를 가져갈 수 있는 위치를 고민하였습니다. 수열이 [V, W, X, Y, Z] 라고할 때 rightInd가 Z를 가르키고 있을 때 leftInd 가 최대 어디까지 있을 수 있을까에 대해서 고민하였습니다.

 

 

 

1. rightInd + 1 을 하였을 때 rightInd가 짝수일 경우는 그냥 옮기고, 홀수일 경우에는 벽을 부술 수 있는 횟수를 차감 합니다.

2. 만약 벽을 부술 수 있는 횟수를 더이상 차감할 수 없다면 while 문을 통해 leftInd를 홀수 쪽으로 옮깁니다. 

   - while이 끝난 후에는 leftInd가 가르키고 있는 값은 무조건 홀수 입니다. 따라서 leftInd += 1을 통해 벽을 부술 수 있는 기회를 1 늘립니다. (while 문 조건에는 rightInd를 넘을 수없다는 조건을 추가해줍니다. )

3. rightInd에서 최대 수열의 길이를 비교합니다. // res = max(res, right - left + 1 - (K - prev))

 

 

코드 전문

import Foundation

func sol() {
  let NK = readLine()!.split(separator: " ").map{Int($0)!}
  let N = NK[0]
  let K = NK[1]
  let arr = readLine()!.split(separator: " ").map{Int($0)!}

  var left = 0
  var right = 0
  var res = arr[0] % 2 == 0 ? 1 : 0
  var prev = K - (arr[0] % 2 == 0 ? 0 : 1)
  while right + 1 < N {
    if arr[right + 1] % 2 == 1 {
      if prev == 0 {
        while left < right && arr[left] % 2 != 1 {
          left += 1
        }
        left += 1
        prev += 1
      }
      prev -= 1
    }
    right += 1
    res = max(res, right - left + 1 - (K - prev))
  }
  print(res)
}
sol()