728x90
백준 22857 - 가장 긴 짝수 연속한 부분 수열(small)
시간 제한 1초, 메모리 제한 1024MB
# 조건
길이가 $N$인 수열 $S$가 있다. 수열 $S$는 1 이상인 정수로 이루어져 있다.
수열 $S$에서 원하는 위치에 있는 수를 골라 최대 $K$번 삭제를 할 수 있다.
예를 들어, 수열 $S$가 다음과 같이 구성되어 있다고 가정하자.
수열 S : 1 2 3 4 5 6 7 8
수열 $S$에서 4번째에 있는 4를 지운다고 하면 아래와 같다.
수열 S : 1 2 3 5 6 7 8
수열 $S$에서 최대 $K$번 원소를 삭제한 수열에서 짝수로 이루어져 있는 연속한 부분 수열 중 가장 긴 길이를 구해보자.
입력
- 수열 S의 길이 N와 삭제할 수 있는 최대 횟수인 K가 공백으로 구분되어 주어진다.
- 두 번째 줄에는 수열 S를 구성하고 있는 N개의 수가 공백으로 구분되어 주어진다.
출력
- 수열 S에서 최대 K번 원소를 삭제한 수열에서 짝수로 이루어져 있는 연속한 부분 수열 중 가장 긴 길이를 출력한다.
# 접근 방법
- N의 제한이 50000이고, K의 제한은 100이다.
- 따라서 모든 경우의 수를 완전 탐색으로 살펴본다면 TL를 받게 된다.
- 이전의 결과 값을 사용하기 위하여 DP를 활용해준다.
- 최대 k번 지울 수 있으므로 2차원 크기가 k+1이고, 1차원의 크기가 N+1인 DP를 생성해준다.
- 이후 입력받은 숫자를 k번씩 순회하며 순회하며 짝수인 경우 dp[i-1][j] + 1을 해준다
- k를 소모하지 않았으므로 직전 값의 지운 횟수에서 + 1
- 홀수인 경우 dp[i-1][j-1]을 해준다.
import sys
sys.stdin = open('input.txt')
si = sys.stdin.readline
N, K = map(int, si().split())
nums = [0] + list(map(int, si().split()))
dp = [[0] * (K+1) for _ in range(N+1)]
for i, j in enumerate(nums):
if not i:
continue
for k in range(K+1):
if not j % 2:
dp[i][k] = dp[i-1][k] + 1
elif k != 0 and j % 2:
dp[i][k] = dp[i-1][k-1]
result = 0
for i in dp:
temp = max(i)
result = max(result, temp)
print(result)
- 아래와 같이 투 포인터로도 풀어줄 수 있다.
- right 포인터가 짝수인 경우 현재 짝수 카운트 +1, right + 1, result 갱
- 아닌 경우, 현재 K가 남아있다면 K-=1, right +=1
- K가 없다면, 현재 left 포인터가 짝수이면 now -= 1, 아니라면 K += 1을 하고 left += 1을 해준다.
# https://www.acmicpc.net/problem/22857
import sys
input = sys.stdin.readline
N, K = map(int, input().split())
arr = list(map(int, input().split()))
left, right = 0, 0
ans, now = 0, 0
while right < N:
if arr[right] % 2 == 0:
now += 1
right += 1
ans = max(ans, now)
else:
if K:
K -= 1
right += 1
else:
if arr[left] % 2 == 0:
now -= 1
else:
K += 1
left += 1
print(ans)
728x90
'ALGORITHM > DP(동적 계획법)' 카테고리의 다른 글
[백준 1890번] 파이썬 - 점프 (1) | 2023.10.28 |
---|---|
[백준 18353번] 파이썬 - 병사 배치하기 (1) | 2023.10.23 |
[백준 14863번] 파이썬 - 서울에서 경산까지 (0) | 2023.09.22 |
[백준 4811번] 파이썬 - 알약 (0) | 2023.09.15 |
[백준 11660번] 파이썬 - 구간 합 구하기5 (0) | 2023.09.11 |