他人の解説記事焼き直しシリーズ
min25さんの記事を読んでできることは知っていたし、確かオイラーでも1度見かけてad-hocに再帰して解いたような気がするんだけど、ちゃんと履修していなかったところ、sounansyaさんによるわかりやすい解説が生えていたので自分用に数式を打ち直したもの。
min25さんの記事より計算量は悪いものの、あちらは実装例なし+2次元FFTとか言っているのでまずはこちらで入門……
他人が書いた数式って気持ちが微妙に違うから、こういう複雑な数式を追うときは自分で書き直したくなるんだよね。
floor sum アルゴリズムとその一般化 #競技プログラミング - Qiita
問題
が与えられるので
を高速に求めたい。
への帰着
を、 となるよう取る。元の式に代入して
を得る。よって以下では であるとする。
主客転倒
floorの部分の値で主客転倒する。取りうる値は 0 以上 以下である。
K=0のとき答えは明らかに0である。以下では K > 0 であるとする。
を、
のとき
と定めると、
「 かつ 」 となることがわかる。
これはfloorとceilの処理に気をつけながら式変形するだけなので詳細は割愛する。
本計算
アーベルの級数変形法(これも主客転倒か?)により
となり再帰的に解くことで求まる。
再帰のベースケースは
- N=0 → 空和なので0
- q=0 →
- (q≠0 かつ K=0 → 0の和なので0) ←これはなくても良い。1回再帰するとN=0になるので
計算量
再帰呼び出しするときの引数はp,qによらずN,M,A,Bのみによるので、 を計算する過程全体で呼び出される引数の種類数はであり、p,qも合わせると評価する関数の値の個数は 個であることがわかる。評価自体は総和が でできるので、全体の計算量は になることが確かめられた。
実装
Pythonでの実装
有理数クラスを使うなどいい加減な実装をしても (p,q)=(5,5), A,B,N,M≦1000 が 100ケースで4秒程度だった。