F - Teleporting Takahashi 2 解説 by sounansya 印刷ページ


公式解説より計算量も悪く、Python だと TLE する別解です。

\(d[i][c]\) を「頂点 \(1\) からちょうど \(c\) 回移動する方法で、\(c\) 回目に辺 \(N+i\) を通るような移動の個数」と定義します。

辺 \(N+i\) を通った後に辺 \(1\) から辺 \(N\) までを何回か使って辺 \(N+j\) を通るには、辺 \(1\) から辺 \(N\) までを通る回数を \(N\) で割ったあまりが \((X_j-Y_i) \bmod N\) である必要があるため、遷移は \(d[j][c+1+(X_j-Y_i) \bmod N+kN] += d[i][c]\) となります。\(+kN\) 部分がそのまま遷移を行うと TLE となりますが、この部分を \(N\) 個飛ばしの累積和として持つことで高速に計算することができます。

以上を適切に実装することでこの問題に正答することができます。計算量は \(O(M^2K)\) です。

実装例(C++)

#include <bits/stdc++.h>
#include <atcoder/all>
using namespace std;
using mint = atcoder::modint998244353;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m, k;
    cin >> n >> m >> k;
    vector<int> x(m), y(m);
    for (int i = 0; i < m; i++) {
        cin >> x[i] >> y[i];
        x[i]--, y[i]--;
    }
    vector d(m, vector<mint>(k + 1));
    vector dd(m, vector<mint>(k + 1));
    for (int i = 0; i < m; i++) {
        if (x[i] + 1 <= k) dd[i][x[i] + 1]++;
    }
    mint ans = 1;
    for (int c = 0; c <= k; c++) {
        for (int i = 0; i < m; i++) {
            if (c + n <= k) dd[i][c + n] += dd[i][c];
            d[i][c] += dd[i][c];
            if (d[i][c] == 0) continue;
            for (int j = 0; j < m; j++) {
                const int cc = c + 1 + (x[j] - y[i] + n) % n;
                if (cc <= k) dd[j][cc] += d[i][c];
            }
            ans += d[i][c];
        }
    }
    cout << ans.val() << '\n';
}

投稿日時:
最終更新: