累積和とかの話

@qnighyさんと@nicinoryuさんの会話が勉強になりそうだったので勝手にまとめました。
5
Masaki Hara @qnighy

@nijinoryu えーと,sumの値は事前計算しておくことができるので計算量は落ちませんか?

2014-01-18 22:27:27
虹の龍@えちえちイラストRTbot @nijinoryu

@qnighy そうでした! O(nm)の処理をした後にO(1)の処理をq回するので、全体ではO(nm+q)でしょうか

2014-01-18 22:30:06
Masaki Hara @qnighy

@nijinoryu 正解です.累積和を求めておくときの事前計算があるので,一回だけ必要なときは無駄ですが,同じデータに対してたくさんクエリが来るときはこのように高速になります.

2014-01-18 22:31:49
虹の龍@えちえちイラストRTbot @nijinoryu

@qnighy ありがとうございます。O(nmq)とO(nm+q)では随分な違いですものね

2014-01-18 22:37:13
Masaki Hara @qnighy

@nijinoryu さて,本題に戻ります.まず,一次元の場合を考えます.数列0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0の累積和はどうなりますか?

2014-01-18 22:26:18
Masaki Hara @qnighy

@nijinoryu OKです.では,さっきの数列のうち2つの項を変更して,0, 0, 0, 1, 0, 1, 0, 0, -1, 0, 0, -1とします.累積和はどのように変わりますか?

2014-01-18 22:30:11
虹の龍@えちえちイラストRTbot @nijinoryu

@qnighy 0,0,0,1,1,2,2,2,1,1,1,0です。 1の後に-1が来る前にもう一度1が来たので、累積和に2が登場しました

2014-01-18 22:35:06
Masaki Hara @qnighy

@nijinoryu もとの数列は「5番目が1増加,11番目が1減少」しました.一方,その累積和は「5番目から10番目までが1ずつ増加した」となりました.OKですか?

2014-01-18 22:37:55
虹の龍@えちえちイラストRTbot @nijinoryu

@qnighy はい。a<bで、a番目が1増加、b番目が1減少すると、その累積和はa番目からb-1番目が1ずつ増加します

2014-01-18 22:43:57
Masaki Hara @qnighy

@nijinoryu では,「a[q]からb[q]-1番目(a[q]<b[q])にそれぞれ1を足してください」というクエリがたくさん来るとします.最終結果だけわかればよいとします.どのようにすると効率的ですか?

2014-01-18 22:46:07
虹の龍@えちえちイラストRTbot @nijinoryu

@qnighy クエリiに対してa[i]番目からb[i]-1番目までに1を足していると、もとの数列の長さをnとして最悪O(nq)かかります。 しかし、数列c[n]を導入して、c[a[i]]に1,c[b[i]]に-1を加える処理をq回行い、c[n]の累積和d[n]をもとの数列に足す

2014-01-18 22:55:55
Masaki Hara @qnighy

@nijinoryu OKです.数列の初期値が0のときはもう少し簡単になりますね.このように,あらかじめ差分だけを記録しておいて最後に累積和を取る方法を,競プロ界隈ローカルな業界用語で「いもす法」と呼ぶ習慣があるので覚えておくと便利かもしれません.

2014-01-18 22:58:52
Masaki Hara @qnighy

@nijinoryu そして,これを2次元に対して適用したものが,Nailsの解説の5ページあたりから解説されているものです.

2014-01-18 23:00:01