公式

C - 花壇の水やり / Watering the Flower Bed 解説 by kyopro_friends


この問題は俗に imos 法と呼ばれる、累積和の逆変換を用いることで解くことができます。

\(M\) 日間合計で各花の高さの増加量が分かれば十分です。よって問題は「\(0\) で初期化された長さ \(N\) の配列に対して、 \(M\) 個の区間加算クエリを処理したあとの、各要素の値を求めよ」と読み替えられます。

配列の階差に注目します。ある区間に定数を加えることは、階差の2箇所に定数を加減することと同値です。

図

よって、区間加算を行う対象の配列の代わりにその階差を管理し、全ての区間加算を処理したあとで階差から元の数列を復元することにより、 \(O(N+M)\) で答えを求めることができます。

実装例 (C++)

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

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

  // 高さの増加量を求める
  vector<long long> a(n+1);
  for(int i=0; i<m; i++){
    int l, r, w;
    cin >> l >> r >> w;
    l--;
    a[l] += w;
    a[r] -= w;
  }
  for(int i=0; i<n; i++){
    a[i+1] += a[i];
  }

  int ans = 0;
  for(int i=0; i<n; i++){
    if(h[i] + a[i] >= t[i]){
      ans++;
    }
  }

  cout << ans << endl;
}

実装例 (Python)

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

# 高さの増加量を求める
A = [0] * (N+1)
for _ in range(M):
  L, R, W = map(int,input().split())
  L -= 1
  A[L] += W
  A[R] -= W
for i in range(N):
  A[i+1] += A[i]

ans = 0
for i in range(N):
  if H[i] + A[i] >= T[i]:
    ans += 1

print(ans)

投稿日時:
最終更新: