公式

B - りんご収穫 / Apple Harvest 解説 by kyopro_friends


この問題は累積和を用いて解くことができます。

以下、数列の添字は \(0\) から始まるものとします。

収穫作業は行えば行うだけ得なので、収穫作業を行う木の本数は \(M\) としてよいです。

各木から出荷できるりんごの個数を表す数列 \(A\) を、

\(A_i=\begin{cases} H_i & H_i\geq K のとき\\ 0 & H_i < K のとき\\ \end{cases}\)

と定めます。求めるのは「\(A\) の連続する \(M\) 要素の和の最大値は?」となります。

数列 \(S\)\(A\) の累積和とします。すなわち

\(S_i=\begin{cases} 0 & i=0 のとき\\ S_{i-1}+A_{i-1} & i>0 のとき \end{cases}\)

と定めます。\(S_i\) は、数列 \(A\) の先頭から \(i\) 項の和になります。定義から \(S\)\(O(N)\) で求めることができます。

このとき、\(A\) の連続する \(M\) 要素の和 \(A_L+A_{L+1}+\dots+A_{L+M-1}\)\(S_{L+M}-S_{L}\)\(O(1)\) で求めることができます。よって \(L\) を全探索することで \(O(N)\) で答えを求めることができます。

実装例 (C++)

#include<bits/stdc++.h>
using namespace std;

int main(){
  int n, m, k;
  cin >> n >> m >> k;
  vector<int>h(n);
  for(int i=0; i<n; i++) cin >> h[i];

  vector<long long>s({0});
  for(int i=0; i<n; i++){
    int a;
    if(h[i] < k){
      a = 0;
    }else{
      a = h[i];
    }
    s.push_back(s[i] + a);
  }

  long long ans = 0;
  for(int i=m; i<=n; i++){
    ans = max(ans, s[i] - s[i-m]);
  }
  cout << ans << endl;
}

実装例 (Python)

N, M, K = map(int, input().split())
H = list(map(int, input().split()))

S = [0]
for h in H:
  a = 0 if h < K else h
  S.append(S[-1]+a)

print(max(S[i] - S[i-M] for i in range(M, N+1)))

投稿日時:
最終更新: