Official

E - Safety Journey Editorial by en_translator


We will try solving this problem with DP (Dynamic Programming).
Let \(dp[i][j]=\) (the number of sequences of towns \((A_0, \ldots A_i)\) such that \(A_0=0\), \(A_i=j\), and for each \(0\leq i'\leq i-1\), \(A_{i'}\) and \(A_{i'+1}\) are connected with a road). Then, \(dp[0][0]=1\), \(dp[0][1]=\cdots=dp[0][N]=0\), and \(dp[i+1][j]\) can be written as

\[dp[i+1][j]=\displaystyle\sum_{j'\in S_j}dp[i][j']\]

where \(S_j=\{j'|\text{Towns }j\text{ and }j'\text{ are connected with a road}\}\).

However, computing this directly requires \(O(N^2K)\) of computation time, which won’t fit in the time limit. Here, what if we transform the expression as

\[dp[i+1][j]=\displaystyle\sum_{j'=1}^Ndp[i][j']-\displaystyle\sum_{j'\in S_j}dp[i][j']\]

where \(S_j=\{j'|\text{Towns }j\text{ and }j'\text{ are not connected with a road}\}\)? Since the first term is independent of \(j\), we have to compute it at most once for each \(i\), and each calculation costs \(O(N)\) time. For the second term, since the sum of numbers of elements of \(S'_j\) over \(j\) is \(2M + N\), so this can also be computed in an \(O(N+M)\) time for each \(i\). (Note that \(j\) itself is included) Therefore, in this case the transition \(i\to i+1\) can be done in an \(O(N+M)\) time, so the total computation time is \(O((N+M)K)\). What we want is \(dp[K][1]\), so we could solved the problem.

Sample code in 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: