
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int T = Integer.parseInt(st.nextToken()); // T분 동안 음식 먹음
int N = Integer.parseInt(st.nextToken()); // 음식 종류
int D = Integer.parseInt(st.nextToken()); // 다이어트 효과 유지 시간
int K = Integer.parseInt(st.nextToken()); // 몇 잔?
int[] time = new int[N];
int[] next = new int[N];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < N; i++) {
time[i] = Integer.parseInt(st.nextToken());
}
Arrays.sort(time);
int[] cnt = new int[N];
int j = 0;
for (int i = 0; i < N; i++) {
while (j < N && time[j] <= time[i] + D - 1) j++;
cnt[i] = j - i;
next[i] = j - 1;
}
int[][] dp = new int[K+1][N+1];
for (int r = 1; r <= K; r++) {
for (int c = N-1; c >= 0; c--) {
int no = dp[r][c+1];
int yes = cnt[c] + dp[r-1][next[c]+1];
dp[r][c] = Math.max(no, yes);
}
}
System.out.println(dp[K][0]);
br.close();
}
}
time 배열 : 음식 먹는 타이밍 저장 후 정렬cnt 배열 : 해당 타이밍에 차를 마시는 경우 영향을 받는 음식의 수next 배열 : 해당 타이밍에 차를 마시는 경우, 차의 영향이 끝나는 인덱스 + 1dp 배열 : cnt 배열 + 그 다음 인덱스에서 한 잔 덜 마실 때의 dp값dp[r][c]는 dp[r-1][...]만 참조하므로,
이전 행만 저장하면 충분합니다.
int[] prev = new int[N+1];
int[] curr = new int[N+1];
for (int r = 1; r <= K; r++) {
for (int c = N-1; c >= 0; c--) {
int no = curr[c+1];
int yes = cnt[c] + prev[next[c]+1];
curr[c] = Math.max(no, yes);
}
int[] tmp = prev;
prev = curr;
curr = tmp;
}
System.out.println(prev[0]);
➡️ 메모리: O(N)
➡️ 시간: 여전히 O(KN) (단, 캐시 효율↑, 실행속도 개선)
다음 상태가 항상 next[c]+1로 점프하므로,
dp[r-1]에 대해 미리 suffix max 배열을 만들어 두면 O(1)로 접근 가능.
for (int r = 1; r <= K; r++) {
int[] suffix = new int[N+2];
for (int c = N-1; c >= 0; c--) {
suffix[c] = Math.max(suffix[c+1], prev[c]);
}
for (int c = N-1; c >= 0; c--) {
int no = curr[c+1];
int yes = cnt[c] + suffix[next[c]+1];
curr[c] = Math.max(no, yes);
}
int[] tmp = prev;
prev = curr;
curr = tmp;
}
suffix 계산은 O(N)r)당 O(N)K가 최대 수천이라면 DP는 이미 한계.[time[i], time[i]+D-1]를 “간격(interval)”로 보고 서로 겹치지 않게 K개를 고르는 최대 카운트 문제로 바꾸면,→ 이분탐색 + DP + 누적합 형태로 O(N log N + K log N)까지 최적화 가능.