この問題は有向非巡回グラフ(DAG)上のDPを問います。
愚直に実装してみたいところですが辺の本数は多くて を超え、かつ移動する経路の数は膨大です。
なのでこのアプローチでは到底、答えを得ることは困難であることが分かります。
以下、 としてクエリ 個当たりの処理の説明を行います。
まずはこの問題に書かれた操作において重要な性質があります。
それは一つの移動方法に対して、「どの道の移動で」走ったか(または歩いたか)の情報は必要なく、「歩いた」回数および「走った」回数さえわかればよいことになります※1。
さらにその つの情報は、その移動で何回移動を行うか、という情報から「走った」回数だけを知るだけでよいことになります。
これを数式に表してみましょう。ある一つの移動方法において、その移動回数は であったとします。
この移動において走った回数を とすれば(歩いた回数は と表せます)、本問題で満たすべき条件式は次のように立式できます:
これを変形することによって を得ます。つまりその移動方法において、走る回数は (以下、この値を とします)回以上でないと条件を満たすような移動を行えないということを意味します。
さらに移動回数は 回ということから、 が成り立ちます。これによって走る回数 に対する条件式を表すことができました。
この条件式を用いることによって、 の値が固定できれば、その移動方法において走る移動が 回以上あるような方法すべてが、今回の問題を満たすようなものになります。
上で立式した条件式において、 の値を固定しないと の具体的な値の条件を計算できません。そのため を求める必要があります。
今回の制約から、与えられる街の構造は有向非巡回グラフ(DAG)とみなすことができます。このグラフ構造では、有向閉路が存在しないことが保証されています。
つまり、ある一つの移動方法において の値は一意に定まることになります※2。
DAGであれば、実は「街 から街 までに移動する方法の数(走る・歩くの要する時間は考慮しない)を求める」といった問題をDPによって求めることができます※3。
またどのような移動であったとしても、ある二つの移動方法において移動回数 が変わらないなら、このDPによって求める「移動方法の個数」を使って容易に計算することができます。
以上、セクション I, II. において の値を固定することにより、今回解く問題は一つの移動方法に対して、次のように言い換えることができます:
これは二項係数を用いて計算することが可能です。
このセクション内で本質的な問題は の値を求めることであり、実はその値は と表せます。そしてこの値を として、次のようなDP配列を定義します:
これを計算することによって、同じ 回の移動であったとしても移動の操作は変わらないことから、全体における移動の選択方法の計算を行うことができます。
つまり、ちょうど 回の移動となるような経路が 通りだけ存在する、ということを用いて、後に示す移動の選び方の組み合わせの個数が容易に計算できるようになります。
ではこのDPの話を深堀りしていきましょう。
まず初期化は、今回求めるものは組み合わせの総数なので
となります※5。
次に遷移について、 はDAGなのでトポロジカルソートによって、一つの頂点からどのような経路をたどるかは一意に定まります※6。
この一意性を利用すれば、 においてトポロジカルソート順に並びかえた頂点列 として、ある頂点 に隣接する頂点集合 とすれば、遷移式は
となります。ここで は移動回数を表すので となります。
このDPによって で計算をすることができます。厳密には、頂点 の頂点の次数 とすれば と表すことができます。今回、制約から「任意の街について、街からつながる道は 本以下」となっているため、時間制限に間に合います。
この計算の結果、求めるのに欲しい情報は となります。
はそのまま移動回数 の値となる他、前に示した通り は移動の方法の数となります。これによって求めたい値をまた取得することができました。
セクション I. で求めた条件式 において、II. によって が固定できるので の値の範囲を具体的な数値を代入しながら計算することができます。
以上の情報を通して、ある つの移動方法(この時の移動回数を とします)に対するこの組み合わせの答えは、条件式に基づいた下限 、上限 として、和の法則よりセクション II. で示した問題★の答えは となります。
そして において 通りだけ同じ移動回数の移動の選び方が存在するので、任意の つの における答えは となります。これが全体の「経路の選び方」の総数です。
回の移動に関して、「ある移動の仕方を選ぶ」場合に対する の答えを で表現して、 に対して とすれば、求める値は
と表せます。
しかし今回、上の計算値を 回のクエリに答える必要があります。
愚直に上の値を計算していると最悪 だけ要することになり、すべてのクエリを制限時間内に処理できなくなってしまいます。
そこで累積和を使って、 の計算を高速化させることを考えます。
これは と固定して と定義し、
の関係式を用いることにより、 の計算を で処理できるようになります※7。
以上でこの値を求めることでこの問題を正解することができます。
これにより、トポロジカルソートやDPを行う前処理で、頂点 の次数 とおいて 、クエリ 回の処理で だけ要することになります。
ゆえに本問題は で解くことができました。本ページ最下部に解答例(C++)を示しています。
※1
その移動方法で走る回数が変わらない限り、どのように道を使って移動しようと結果的に要する時間は変わりません。この性質を利用しています。
※2
制約から「同じ街は 回以上訪れることはできない」と書かれています。この情報から、ある街から街まで移動する方法は一意に定まり、他の移動方法は存在しないことになります。
これは、街 から街 まで 個の街を経由して移動する方法の数は一意に定まるということを意味しています( )。
※3
DPは、遷移の形がDAGとして表現できるような問題で扱うことができます(逆にそうでないような問題は適用できない...?)。
今回は明らかにDAG構造を成しているため、適用できます。
※4
一般に「 回以上 回の移動の方法は何通りか」などといった、回数が範囲で示されている場合は「それぞれちょうど 回の移動を行った場合の方法は何通りか」のような形で、ちょうど~回といった文に言い換えることができます。今回でもこれを利用して解きます。
※5
の場合に となるのは、頂点 から頂点 (移動回数 )に移動する方法の数は明らかに 通りであるためです。このとき は0-indexedであることに注意してください。
※6
厳密にはトポロジカルソートを行った結果は一意とは限らない可能性もあります(諸説あり)。しかしソートをされているならどの順番であったとしても正確な答えは求められることは保証されるので、今回のアプローチは適切です。
※7
すべての に対して前処理を行うので、前処理で最悪 だけかかります。