https://soundhound2018-summer-final-open.contest.atcoder.jp/tasks/soundhound2018_summer_final_c
わりとすっきり解けた気がする。思考プロセス書きます。
N,D<=30
->分割統治?
->直線にしてみる?
->とりあえず緩和して最短距離がD以上のグラフの個数を数えてみる?
-->1から2への全ての経路がD以上になって見やすくなった。
-->bellman-ford的にdp?bfsっぽく距離1,2,3...の点と順番に見ていく?
--->後者っぽい。
--->dp[i][v][w]:=距離iの点まで見て、v個点が使われている。距離i-1で使われた点はw個。この時の場合の数 でできた。
--->緩和いらなくて草。
->こっからバグらせるんだよね。
-->dpにかかる係数をA,Bみたいに文字おいてごまかしたらわかりやすくなった。
-->困難は分割せよってそれ一番言われてる。
int N, D; ll dp[41][41][41]; void solve() { cin >> N >> D; C_init(N); dp[0][1][1] = 1; rep(i, 0, D) { rep(v, 1, N) { rep(u, 1, N) { if(!dp[i][v][u]) continue; rep(w, 1, N) { ll A = mod_pow((mod_pow(2, u) - 1 + mod) % mod, w); ll B = mod_pow(2, w * (w - 1) / 2); ll E; if(i < D - 1) { if(N - v - 1 - w >= 0) E = C(N - (v + 1), w); else continue; } else if(i == D - 1) { if(N - v - w >= 0) E = C(N - (v + 1), w - 1); else continue; } else { if(N - v - w >= 0) E = C(N - v, w); else continue; } ADD(dp[i + 1][v + w][w], dp[i][v][u] * A % mod * B % mod * E % mod); } } } } ll res = 0; rep(i, 1, N + 1) { rep(j, 1, N) { ADD(res, dp[D][i][j] * mod_pow(2, j * (N - i) + (N - i) * (N - i - 1) / 2) % mod); } } cout << res << "\n"; }