添字迷子にならないための練習
以下の記事を見ながら練習したことのメモ。
現状、以下の記事内の
何も考えずに AC するまで [i] [i+1] [i-1] などを適当に書き換えるような癖はつけない方がいいと思います。
みたいなことが度々あるので、少しずつ書き改めていく。
※練習のため、上記の記事からの新規性はほぼゼロです。
累積和
実装
int main() { int n; cin >> n; // 元の配列 vector<int> a(n); rep(i, 0, n) cin >> a[i]; a.insert(a.begin(), 0); // 累積和 vector<int> sum = a; rep(i, 1, n + 1) sum[i] += sum[i - 1]; // 逆からの累積和 vector<int> t(n + 1, sum[n]); rep(i, 1, n + 1) t[i] -= sum[i]; // 階差 vector<int> diff(n + 1); rep(i, 1, n + 1) diff[i] = a[i] - a[i - 1]; // 階差から元の配列を復元 vector<int> b(n + 1); b[0] = 0; rep(i, 1, n + 1) b[i] = b[i - 1] + diff[i]; rep(i, 0, n + 1) cout << setw(2) << a[i] << " "; cout << ":元の配列" << endl; rep(i, 0, n + 1) cout << setw(2) << sum[i] << " "; cout << ":累積和" << endl; rep(i, 0, n + 1) cout << setw(2) << t[i] << " "; cout << ":逆からの累積和" << endl; rep(i, 0, n + 1) cout << setw(2) << sum[i] + t[i + 1] << " "; cout << ":a[i]を覗いた累積" << endl; rep(i, 0, n + 1) cout << setw(2) << diff[i] << " "; cout << ":階差" << endl; rep(i, 0, n + 1) cout << setw(2) << b[i] << " "; cout << ":階差から元の配列を復元" << endl; }
ポイント
- 元の配列の初項を 0 にする
- 入力はいつもどおり, サイズ n で受け取れる. あとから最初の要素に 0 を insert
- 累積和の配列は a をコピーするだけなので, 長さは考えなくていい
- 累積和の計算は前から順番に走査しながら足していくだけ
- 区間和は半開区間で求まる. s[i] は 区間[l,r)の和
- つまり, 0-indexd の[l, r]の累積和は, [l, r+1)なので, sum[r+1] - sum[l] で求まる
- 階差も初項 0 で考える
練習問題の提出
- https://atcoder.jp/contests/abc084/submissions/33233395
- https://atcoder.jp/contests/abc122/submissions/33238186
- https://atcoder.jp/contests/agc023/submissions/33285993
二分探索
(練習したら書く)
尺取法
(練習したら書く)