TOP > 動的計画法 スライド最小値(Slide-Min) 2018/12/28 • ei1333 説明 スライドする区間の最小値を求める。 計算量 $O(N)$ 実装例 slide_min($v$, $k$): 配列 $v$ の幅 $k$(1-indexed) の各連続区間についての最小値を返す。 template< typename T > vector< T > slide_min(const vector< T > &v, int k) { deque< int > deq; vector< T > ret; for(int i = 0; i < v.size(); i++) { while(!deq.empty() && v[deq.back()] >= v[i]) { deq.pop_back(); } deq.push_back(i); if(i - k + 1 >= 0) { ret.emplace_back(v[deq.front()]); if(deq.front() == i - k + 1) deq.pop_front(); } } return ret; } 検証 AtCoder CODE FESTIVAL 2016 Tournament Round 3 A - ストラックアウト int main() { int N, M, K, A[100000]; cin >> N >> M >> K; for(int i = 0; i < N; i++) { cin >> A[i]; } vector< int64 > dp(N); for(int i = 0; i < N; i++) { dp[i] = A[i]; } for(int i = 1; i < K; i++) { vector< int64 > dp2(N); reverse(begin(dp), end(dp)); dp.resize(N + M - 1); reverse(begin(dp), end(dp)); auto p = slide_min(dp, M); for(int j = i; j < N; j++) { dp2[j] = max(dp2[j], p[j - 1] + 1LL * (i + 1) * A[j]); } dp.swap(dp2); } cout << *max_element(begin(dp), end(dp)) << endl; }