// https://atcoder.jp/contests/past202206-open/tasks/past202206_c use proconio::input; use std::{collections::VecDeque, i64}; fn main() { input! { n: usize, m: usize, a: [[i64; m]; n], } let mut dp: Vec> = vec![vec![i64::MAX;m]; n]; for j in 0..m { dp[0][j] = 0; } // 各m部屋について1階からn階まで取り壊した時のAを計算(累積話) let mut cum_a_list: Vec> = vec![vec![i64::MAX;m]; n]; for j in 0..m { let mut cum_a = 0; for i in 0..n { cum_a += a[i][j]; cum_a_list[i][j] = cum_a; } } let mut min_cells = vec![vec![i64::MAX;m]; n]; let mut min_cols = vec![i64::MAX;m]; for i in 1..n { for j in 0..m { // dp[i][j]の値を計算する if m > 1 { // 途中の階からエレベーターを作る if i > 1 { let x = min_cols[j] + cum_a_list[i][j]; dp[i][j] = dp[i][j].min(x); } } // 1階からきちんとエレベータを作る dp[i][j] = dp[i][j].min(cum_a_list[i][j]); } // 次の階以降の計算をするための準備を実施 let mut backwards = vec![0; m]; let mut buck_min = i64::MAX; for j in (0..m).rev() { buck_min = buck_min.min(dp[i][j]); backwards[j] = buck_min; } let mut forward_min = i64::MAX; for j in 0..m { if j + 1 < m { min_cells[i][j] = forward_min.min(backwards[j + 1]); } else { min_cells[i][j] = forward_min; } forward_min = forward_min.min(dp[i][j]) } for j in 0..m { min_cols[j] = min_cols[j].min(min_cells[i][j] - cum_a_list[i - 1][j]); } } let answer = dp[n - 1].iter().min().unwrap(); println!("{}", answer); }