この記事でやること
数列の区間に等差数列を加算するクエリを高速に処理する方法を解説します。
具体的には、数列 をで初期化し、以下のクエリを 回処理した後の数列を取得することを、全体 で行います:
注意事項
いもす法について
おなじみのやつですが、考え方が非常に重要なので確認しておきます。
いもす法は区間全体に同じ数字を加算をします。このとき、各クエリでは「最後に累積和を取ることで元の数列が復元できるような、情報量を削減した数列」を作っていきます。
ということは、同じように「最後に累積和をとることで等差数列を加算した数列が復元できるような、情報量を削減した数列」を作ることができればよさそうです。
発想:2回累積和を取る
先ほどの画像の数列に対し、もう1度累積和を取ってみます。
等差数列が出てきましたね。これを逆に言い換えれば、「2度累積和を取ることで等差数列が復元できるような、情報量を削減した数列」が存在しそうな気がしてきませんか?
というわけで、実際にそのような数列を元の等差数列から構築してみましょう。
初項が0の場合
まずは初項が0の場合を考えます。これは簡単で、下記の画像の一番上の行が作りたかった数列となります。
具体的な処理を一般的に書くと、 に対しては、
とすればよいです。
初項が一般の場合
「初項が0の場合」に、初項のズレを加えていい感じに調整してあげればよいです。
具体的な処理を一般的に書くと、 に対しては、
とすればよいです。
ソースコード
例題
略解
「順送りボタン」のみを使う場合にボタンを押す回数から、「お気に入りボタン」を使うことで削減できる回数を引くと考えます。
各 に対し、 の間でお気に入りボタンを使った際に削減できる回数は、下図のように等差数列で定まります。(実際は の場合もあり、その場合は等差数列が2つに分断されます。)
あとは、各 に対してこれら削減回数の和を位置ごとに取り、maxとなる位置にお気に入りボタンを設定するのが最適となります。