E - Safety Journey Editorial by mechanicalpenciI
動的計画法でこの問題を解くことを考えます。
\(dp[i][j]=(A_0=0\) かつ \(A_i=j\) であるような都市の列 \((A_0, \ldots A_i)\) であって、各 \(0\leq i'\leq i-1\) について、 \(A_{i'}\) と\(A_{i'+1}\) が道でつながっているようなものの数)とします。
すると、\(dp[0][0]=1\) , \(dp[0][1]=\cdots=dp[0][N]=0\) であり、
\(dp[i+1][j]\) は\(S_j=\{j'|都市j と都市j 'は道でつながっている\}\)を用いて、
\[dp[i+1][j]=\displaystyle\sum_{j'\in S_j}dp[i][j']\]
と書く事が出来ます。
しかしこれをそのまま計算すると、\(O(N^2K)\) の計算量がかかり、時間制限に引っかかってしまいます。そこで、 これを\(S'_j=\{j'|都市j と都市j 'は道でつながっていない\}\)を用いて、
\[dp[i+1][j]=\displaystyle\sum_{j'=1}^Ndp[i][j']-\displaystyle\sum_{j'\in S_j}dp[i][j']\]
と書きかえてみます。 第 \(1\) 項は \(j\) によらないため、各 \(i\) ごとに一度計算すればよく、計算には \(1\) 回当たり \(O(N)\) がかかります。 第 \(2\) 項は \(S'_j\) の要素数がすべての \(j\) についてあわせて \(2M+N\) 個しか無い事からこちらも各 \(i\) について \(O(N+M)\) で計算できます。\((j\) 自身が含まれることに注意) よってこの場合は \(i\to i+1\) の遷移が\(O(N+M)\) で行えるため、全体で \(O((N+M)K)\) であり、求めたいものは \(dp[K][1]\) であるため、これでこの問題を解く事が出来ました。
C++による実装例:
#include <bits/stdc++.h>
using namespace std;
#define N 6000
#define MOD 998244353
#define ll long long
#define rep(i, n) for(int i = 0; i < n; ++i)
int main(void) {
int n, m, k, u, v, sz;
vector<int>e[N];
ll x, y, z, s;
ll dp[N];
ll dp2[N];
cin >> n >> m >> k;
rep(i, m) {
cin >> u >> v;
e[u - 1].push_back(v - 1);
e[v - 1].push_back(u - 1);
}
rep(i, n)dp[i] = (ll)0;
dp[0] = (ll)1;
rep(i, k) {
s = (ll)0;
rep(j, n)s += dp[j];
rep(j, n) {
dp2[j] = s - dp[j];
sz = e[j].size();
rep(ii, sz)dp2[j] -= dp[e[j][ii]];
dp2[j] %= MOD;
}
rep(j, n)dp[j] = dp2[j];
}
cout << dp[0] << endl;
return 0;
}
posted:
last update: