この記事で使うアルゴリズム
累積和
いもす法
はじめに
カテゴリー競プロ初中級者100問では、Qiita
にて@e869120
さんがレッドコーダーが教える、競プロ・AtCoder上達のガイドライン【中級編:目指せ水色コーダー!】としてまとめられている100問をPython
で解いています。
全問題の一覧はこちらです
問題
https://atcoder.jp/contests/abc014/tasks/abc014_3
この問題では累積和を応用したいもす法というアルゴリズムで解くことができます。
方針
要素数1000000
のカウンタを用意して、アンケート毎に対象の色をカウントアップすると、計算量はO(1000000n)
となり間に合いません。そこでいもす法
というテクニックを利用します。
いもす法
いもす法は、配列上の連続する区間にある同じ数を足したい
時に有効なテクニックです。累積和の逆のようなテクニックです。例を使って説明します。
まずは累積和のおさらいです。下記のようなリストA
を考えます
1 | A = [2, 3, 0, 1, 2] |
A
の累積和S
は以下のようになりますね。
1 | A = [2, 3, 0, 1, 2] |
さて次に累積和の逆を考えます。
1 | S = [0, 0, 1, 1, 1, 0, 0] |
このような累積和S
を与えるA
はどのようになるでしょうか。
1 | S = [0, 0, 1, 1, 1, 0, 0] |
このようになるはずです。
さて、先ほどのS
のような配列が複数(S1~S3)
あり、それらを足したい状況を想定しましょう。
ただし、まだ配列の形で保持しておらず、以下のように値が1
となっている箇所を示す形の情報だとします。
1 | S1: 2~4 |
この時、配列にもし展開すると下記のようになります。
1 | S1 = [0, 0, 1, 1, 1, 0, 0] |
これらの和S
を求めようとすると配列の数をN
、各配列の要素数をK
として計算量はO(NK)
となります。
一方で、先ほどのように累積和がS
となるようなA
を考えます。先ほどの1となっている箇所を示す形の情報
を元にするとAの作成コストは、O(N+K)
です。
1 | A = [0, 0, 2, 1, 0,-1,-2] |
この累積和を求めると、
1 | A = [0, 0, 2, 1, 0,-1,-2] |
となります。これでより少ない計算量O(N+K)
でS
を求めることができました。
コード
今回の問題は、まさにいもす法
の典型問題です。以下のようにシンプルに実装できます。
1 | import itertools |
記事情報
- 投稿日:2020年5月5日
- 最終更新日:2020年5月8日