## https://yukicoder.me/problems/no/3368 from collections import deque MAX_INT = 10 ** 18 MIN_INT = - 10 ** 18 def solve(N, M, C, X, A, min_value): # 洗濯できる食べ物の種類を位置ごとに選定 enables = [] for i in range(N): row = [] for j in range(M): if A[i][j] >= min_value: row.append(j) enables.append(row) # keyは state , j * 2 + [すでに隣接するアイテムがあるかないかフラグ] def calc_best_3(dp): best_3 = [MAX_INT] * (3 * 2) for state, x_value in dp.items(): for k in range(3): if best_3[2 * k] > x_value: for k_ in reversed(range(k, 2)): for l in range(2): best_3[2 * (k_ + 1) + l] = best_3[2 * k_ + l] best_3[2 * k] = x_value best_3[2 * k + 1] = state break return best_3 row = enables[0] dp = {j * 2 :1 for j in row} best_3 =calc_best_3(dp) for i in range(1, N): new_dp = {} for j in enables[i]: # 異なる食べ物の種類からの遷移 for k in range(3): x_value = best_3[2 * k] state = best_3[2 * k + 1] prev_j = state // 2 has_same_near = state % 2 if best_3[2 * k + 1] == MIN_INT: break if prev_j != j: new_x_value = x_value + 1 new_state = 2 * j else: continue if new_state not in new_dp: new_dp[new_state] = MAX_INT new_dp[new_state] = min(new_dp[new_state], new_x_value) # 同じ食べ物の種類を並べる target_prev_state = 2 * j + 1 if target_prev_state in dp and A[i][j] - C >= min_value: new_x_value = dp[target_prev_state] new_state = 2 * j + 1 if new_state not in new_dp: new_dp[new_state] = MAX_INT new_dp[new_state] = min(new_dp[new_state], new_x_value) target_prev_state = 2 * j if target_prev_state in dp and A[i][j] - C >= min_value and A[i - 1][j] - C >= min_value: new_x_value = dp[target_prev_state] - 1 new_state = 2 * j + 1 if new_state not in new_dp: new_dp[new_state] = MAX_INT new_dp[new_state] = min(new_dp[new_state], new_x_value) dp = new_dp best_3 = calc_best_3(dp) for value in dp.values(): if 0 <= value <= N - X: return True return False def main(): N, M, C, X = map(int, input().split()) A= [] for _ in range(N): A.append(list(map(int, input().split()))) max_a = -float("inf") min_a = float("inf") for row in A: max_a = max(max_a, max(row)) min_a = min(min_a, min(row) - C) low = min_a high = max_a while high - low > 1: mid = (high + low) // 2 if solve(N, M, C, X, A, mid): low = mid else: high = mid if solve(N, M, C, X, A, high): print(high) else: print(low) if __name__ == '__main__': main()