競技プログラミング練習会
2020 Normal
第2回 累積和, しゃくとり法
担当 : zeke
自己紹介
自己紹介
- 京都大学工学部工業化学科 2回生
- 本名:岡島 和希
- AtCoder:水色
- C++で書いてます、Pythonは読むだけなら…
- 昨日ゲームAIを触ったらすごい楽しくてさっきまでやってた
- みなさん、もっとわいわいしませんか?
KMC-ID : zeke

slack(内部チャット)
皆さんの自己紹介もお願いします。
- 名前(部員の方はKMC-ID)
- 所属(大学など)
- 使える言語や使う予定の言語
- プログラミング経験や競プロの経験(もちろんなくても大丈夫!)
- 趣味・特技・意気込みなど
- 何か言いたいこと(あれば)
あくまで一例ですが、下を参考に
今日の内容
今日の内容
-
累積和
-
いもす法
-
しゃくとり法
-
コンテスト!
今日の内容に入る前に
前提知識
配列書けますか?
計算量について分かっているとよい
区間問題
- 区間
- 数学と同じ
-
区間に含まれる要素
- ある配列に関して、インデックス(添字)が指定された区間内である要素の集合
- 区間に関する問題
- ある配列が与えられ、複数の区間に対してなんらかの数値を求める問題
- 区間に含まれる要素の和 など
- ある配列が与えられ、複数の区間に対してなんらかの数値を求める問題
区間
- 区間に関する問題で使える手法
- 累積和
- いもす法
- しゃくとり法
- セグメント木
- Binary Indexed Tree (BIT)
- 平方分割
- ...
区間問題
累積和
- 累積和とは
- 連続する区間の和を高速で求める手法
- 先頭から各要素までの和(=累積和)を利用する
- 実は和以外にも使えるらしい
- (逆演算が存在すれば)
累積和
- 使える状況
- 区間和を大量に求めたい時
- etc...
例題
長さ の数列 { } が与えられる。
それに対し 個のクエリが与えられる。
各クエリでは2整数 が与えられるので、
区間の和 を求めよ。
制約
問題文
実行時間制限: 2 sec / メモリ制限: 1024 MB
- 毎回言われた通り i から j までの要素を足していく
- i = 1 , j = N の時、N 回足さなければいけない
- つまりクエリごとに最悪 かかる
- これが Q 回繰り返されると
- よって計算量は最悪
間に合わない!!
解法1:愚直解
- 準備として先頭から各要素までの部分和(=累積和)を求めておく
- その部分和の配列を{ }とし、もとの配列を{ }とする
- S[i] := 半開区間 [0, i) における部分和
- つまり
解法2:累積和
累積和
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ||
|---|---|---|---|---|---|---|---|---|---|
| 配列 | 2 | 0 | -2 | -4 | 2 | 4 | 10 | -5 | |
| 累積和 |
解法2:累積和
解法2:累積和
S[0]=0;
for(int i=1;i<=N;i++){
S[i]=S[i-1]+a[i-1];
}{ }は以下のように求めることができる
計算量は
解法2:累積和
- この{ }を使って、閉区間[ i , j ]の要素の和を求めたい
- から までの和なので、 とすれば求められる
- 計算量は
解法2:累積和
なぜなら
ー
解法2:累積和
- まず累積和を求めるのに
- 一つのクエリを処理するのに
- それを Q 回行うので、クエリの処理全体で
- よって、全体の計算量は
- すなわち 程度
- これなら十分間に合う!
二次元累積和
- さっきは一次元領域だった
- 区間の和を高速に求めた
-
二次元領域でも累積和が使える
- 長方形領域内の和を高速に求める
- 考え方はさっきとほとんど同じ
二次元累積和
累積和の準備
全ての行(横方向)に対して累積和を取る
Step 2で求めた累積和を用いて、さらに全ての列(縦方向)に対して累積和を取る
出来上がった二次元累積和を用い、長方形領域内の和を求める
二次元累積和
Step 1
Step 2
Step 3
Step 4
使い方
Step 1 累積和の準備
- もとの二次元配列よりも縦横それぞれ1つだけ大きい配列を作っておく
-
最初の行・最初の列を 0 で埋める
- 半開区間を表現するため
いめーじ
Step 1 累積和の準備
| {a} | 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|
| 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 1 | 2 | 8 | -1 | 3 | 0 | -3 |
| 2 | 4 | 8 | -3 | 8 | 8 | 5 |
| 3 | 1 | 1 | 7 | -3 | 6 | 1 |
| 4 | -2 | 5 | 6 | -3 | 0 | -2 |
| 5 | -4 | 3 | 2 | 0 | -1 | 2 |
これが元の配列a だとすると...
Step 1 累積和の準備
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
こうなります(この配列を説明上a'とする)
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 2 全ての行に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 2 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 4 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 1 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 2 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 4 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 1 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 2 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 4 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 1 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 4 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 1 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 4 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 1 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 11 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 1 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 11 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 1 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 10 | 9 | 12 | 12 | 9 |
| 3 | 0 | 11 | 12 | 9 | 17 | 25 | 30 |
| 4 | 0 | 12 | 2 | 9 | 6 | 12 | 13 |
| 5 | 0 | -2 | 3 | 9 | 6 | 6 | 4 |
| 6 | 0 | -4 | -1 | 1 | 1 | 0 | 2 |
Step 3 全ての列に対して累積和を取る
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 15 | 11 | 14 | 21 | 20 |
| 3 | 0 | 11 | 27 | 20 | 31 | 46 | 50 |
| 4 | 0 | 12 | 29 | 29 | 37 | 58 | 63 |
| 5 | 0 | 10 | 32 | 38 | 43 | 64 | 67 |
| 6 | 0 | 6 | 31 | 39 | 44 | 64 | 69 |
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 15 | 11 | 14 | 21 | 20 |
| 3 | 0 | 11 | 27 | 20 | 31 | 46 | 50 |
| 4 | 0 | 12 | 29 | 29 | 37 | 58 | 63 |
| 5 | 0 | 10 | 32 | 38 | 43 | 64 | 67 |
| 6 | 0 | 6 | 31 | 39 | 44 | 64 | 69 |
さて、出来上がった配列 は何を表しているのか?
例えば は から までの和だった
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
は に から までの和を足したものだった
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
つまり は から までを足したもの!
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
は に から までの和を足したものだった
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
つまり は から までを足したもの!
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
| {S} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 5 | 2 | 2 | 9 | 11 |
| 2 | 0 | 7 | 15 | 11 | 14 | 21 | 20 |
| 3 | 0 | 11 | 27 | 20 | 31 | 46 | 50 |
| 4 | 0 | 12 | 29 | 29 | 37 | 58 | 63 |
| 5 | 0 | 10 | 32 | 38 | 43 | 64 | 67 |
| 6 | 0 | 6 | 31 | 39 | 44 | 64 | 69 |
さて、出来上がった配列 は何を表しているのか?
=> から までの総和を表している
Step 4 長方形領域内の和を求める
例えば、以下の領域の和を求めたい
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 4 長方形領域内の和を求める
この領域の総和( )から...
現在の範囲
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
| {a} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 4 長方形領域内の和を求める
この領域の総和( )を引き...
現在の範囲
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
| {a} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 4 長方形領域内の和を求める
さらにこの領域の総和( )も引き...
現在の範囲
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
| {a} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 4 長方形領域内の和を求める
2回引かれたこの領域の総和( )を足すと...
現在の範囲
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
| {a} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
Step 4 長方形領域内の和を求める
この領域の総和が求まる!
| {a'} | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 5 | 0 | -3 | 0 | 7 | 2 |
| 2 | 0 | 2 | 8 | -1 | 3 | 0 | -3 |
| 3 | 0 | 4 | 8 | -3 | 8 | 8 | 5 |
| 4 | 0 | 1 | 1 | 7 | -3 | 6 | 1 |
| 5 | 0 | -2 | 5 | 6 | -3 | 0 | -2 |
| 6 | 0 | -4 | 3 | 2 | 0 | -1 | 2 |
- つまり、 の総和を求めたかったら...
二次元累積和
で求まる! ( )
- 計算量は... (縦 W, 横 H, クエリの数 Qとする)
- Step 1 で
- Step 2 で
- Step 3 で
- Step 4 で
- よって全体の計算量は
二次元累積和
いもす法
- いもす法とは
- 累積和の応用
- 「最後に累積和をとれば求めたい数列になる」ようにすることで、区間に対する書き換えを 高速に実行できる
いもす法
- 使える状況
- 区間に対する書き換えを大量に行いたい時
- etc...
例題
あなたは店を経営している。訪れた 人の客について入店時刻 と出店時刻 が与えられる。
同時刻に店にいた客の数の最大値はいくらか。
同時刻に入店や出店がある場合、まず出店から行われるとする。
制約
問題文
実行時間制限: 2 sec / メモリ制限: 1024 MB
- 長さ の配列 を用意する
- は時刻 に店にいたお客さんの数とする
- が求まれば、同時刻に店にいた客の数の最大値が求まる
- よって を求めよう!
例題
方針
-
と が与えられるごとに、 の範囲の に 1 を足す
- を含まないのは出店が先に行われるから
- 最悪 回の足し算を 人分する必要があるので、計算量は
- よって となるため間に合わない
解法1 愚直解
- 新しい配列 を用意して、 と が与えられるごとに、 を +1して を -1 する
- 全て終わったら累積和をとり、出来た配列を とする
- これなら で くらいなので大丈夫
- 詳しくは いもす法解説ページ を参照
解法2 いもす法
- なぜこれで求まるのか
- 例えば に +1すると、累積和を取った後の配列では 全てに +1される
- 同様に に -1すると、累積和を取った後の配列では 全てに -1される
- つまり に +1、 に -1すると、累積和を取った後の配列では に +1される
- 店にいた時刻の区間全てに +1されている
解法2 いもす法
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ||
|---|---|---|---|---|---|---|---|---|---|
| クエリ | |||||||||
| いもす | |||||||||
| 累積処理後 |
図解
しゃくとり法
- しゃくとり法とは
- 連続する区間の和を高速で求める手法
- 区間の右端を伸ばしたり左端を縮めたりする
- 尺取り虫に似ている
- 区間の幅を固定する方法と、伸ばせるだけ伸ばす方法がある
しゃくとり法
- 使える状況
- 区間和を大量に求めたい時
- etc...
例題1
長さ の数列 { } が与えられる。
その数列の連続する 個の整数の和の最大値を出力せよ。
制約
問題文
実行時間制限: 2 sec / メモリ制限: 1024 MB
- 和をとる開始点 を定める
- そこから 個の和を順に足して求める ( )
- 全体で となる
- これは最悪 で、間に合わなさそう
解法1 愚直解
- 前処理として累積和を求めておく ( )
- 和をとる開始点 を定める
- そこから 個の和を累積和で求める ( )
- 全体で となる
- 十分間に合う
解法2 累積和
- まず、 から までの和をとる ( )
-
次に区間を一つ先にずらし、 から までの和を求めよう
- 先の和から を引いて を足せばよい ( )
- 先頭を1つ伸ばして、末尾を一つ縮める
- このようにして一つずつずらしていき、最大値を更新していく ( )
- 全体で となる
- わずかに累積和より高速
解法3 しゃくとり法
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:3
和の最大値:3
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:ー
和の最大値:3
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:ー
和の最大値:3
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:11
和の最大値:11
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:ー
和の最大値:11
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:ー
和の最大値:11
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和: 9
和の最大値:11
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:ー
和の最大値:11
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和:ー
和の最大値:11
解法3 しゃくとり法
| 2 | 5 | -4 | 10 | 3 | -5 |
例:n=6, k=3
現在の和: 8
和の最大値:11
- この問題では累積和を使っても、しゃくとり法を使ってもどちらでも良い
- 先に思いついた方を使って大丈夫
解法3 しゃくとり法
例題2
長さ の数列 { } が与えられる。
連続部分列で総和が 以上になるもののうち、長さが最小となるものの長さを出力せよ。
制約
問題文
実行時間制限: 2 sec / メモリ制限: 1024 MB
- 左端 と右端 を決める
- 決め方は 通りくらい
- 決めたら から までを愚直に足し算する
- 最悪長さ になるので
- 全体で となる
- なのでまず間に合わない
解法1 愚直解
解法1 愚直解
ここは改良できる
- 左端 と右端 を決める
- 決め方は 通りくらい
- 決めたら から までを愚直に足し算する
- 最悪長さ になるので
- 全体で となる
- なのでまず間に合わない
- 事前に累積和を計算しておく ( )
- 左端 と右端 を決める
- 決め方は 通りくらいある
- 累積和で和を求める ( )
- 全体で となる
- なので、まだ厳しい
解法2 累積和
- 事前に累積和を計算しておく ( )
- 左端 と右端 を決める
- 決め方は 通りくらいある
- 累積和で和を求める ( )
- 全体で となる
- なので、まだ厳しい
解法2 累積和
ここも改良できる
- 事前に累積和を計算しておく ( )
-
より和は 単調増加
- よって を越える位置を二分探索できる!
- 左端 を決める
- 決め方は 通りある
- を越える最小の を二分探索で見つける ( )
- 全体で となる
- なので、これなら間に合う
解法3 累積和+二分探索
- 本番でこの方法が思い付けたなら 大正解 です
- 二分探索って何?
- 来週やります!お楽しみに!
解法3 累積和+二分探索
- 左端 と右端 を決める
- 決め方は 通りくらい
- 決めたら から までを愚直に足し算する
- 最悪長さ になるので
- 全体で となる
- なのでまず間に合わない
解法1 愚直解
- 左端 と右端 を決める
- 決め方は 通りくらい
- 決めたら から までを愚直に足し算する
- 最悪長さ になるので
- 全体で となる
- なのでまず間に合わない
解法1 愚直解
ここを改良しよう
解法4 愚直解(改良版)
- 左端 を決める
- 決め方は 通り
- 決めたら から 1 つずつ右に伸ばしていく
- 和が を越えたらストップ
- 愚直に足し算をすると最悪長さ になるので
- 全体で となる
- なのでまだ間に合わない
解法4 愚直解(改良版)
今度はここを改良しよう
- 左端 を決める
- 決め方は 通り
- 決めたら から 1 つずつ右に伸ばしていく
- 和が を越えたらストップ
- 愚直に足し算をすると最悪長さ になるので
- 全体で となる
- なのでまだ間に合わない
解法5 しゃくとり法
- 最初は のみ長さ 1 の区間で考える ( 左端l=0, 右端r=0 )
- 区間の和の大きさにより場合分け
- 現在の区間の和が 未満 → 右を1つ伸ばして和を更新 ( r++ )
- 現在の区間の和が 以上 → 左を1つ縮めて和を更新 ( l++ )
- 更新後、和が 以上だったら現在の長さで長さの最小値を更新
- これを繰り返して一番右を越えようとしたところで終了
- 全体で で解ける
- なので余裕
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:4 < S
長さの最小値:ー
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:6
長さの最小値:ー
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:6 < S
長さの最小値:ー
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:11
長さの最小値:ー
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:11 S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:7
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:7 < S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:8
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:8 < S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:15
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:15 S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:13
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:13 S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:8
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:8 < S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:11
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:11 S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:10
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:10 < S
長さの最小値:3
解法5 しゃくとり法
| 4 | 2 | 5 | 1 | 7 | 3 |
例:n=6, S=11
現在の和:終了
長さの最小値:3
解法5 しゃくとり法
解法5 しゃくとり法
- 最初は のみ長さ 1 の区間で考える ( 左端l=0, 右端r=0 )
- 区間の和の大きさにより場合分け
- 現在の区間の和が 未満 → 右を1つ伸ばして和を更新 ( r++ )
- 現在の区間の和が 以上 → 左を1つ縮めて和を更新 ( l++ )
- 更新後、和が 以上だったら現在の長さで長さの最小値を更新
- これを繰り返して一番右を越えようとしたところで終了
- 全体で で解ける
- なので余裕
解法5 しゃくとり法
- なぜ なのか?
- はじめは
- 最後は
- 一回の操作で か どちらかを1増やす
- つまり操作の回数は最大で 回
- 定数は無視するので
終わり!
解説して欲しいものありますか?
ごはん食べよう!!!
(おごりは資金が底を尽きたため終了しました)
コンテスト
コンテスト
参考文献
Copy of 第2回:累積和, しゃくとり法
By kmc_procon2020
Copy of 第2回:累積和, しゃくとり法
発表日時 2019年4月19日(金) 18:30-21:00 https://onlinejudge.u-aizu.ac.jp/beta/room.html#kmc2019_n_2
- 168