公式

G - Replace 解説 by en_translator


Consider a DP (Dynamic Programming) to find the minimum cost \(dp[i][j][c]\) to obtain the substring \(T_iT_{i+1}\ldots T_j\) of \(T\) from a single character \(c\) (or \(+\infty\) if impossible).
Here, we compute another DP at the same time, where we find the minimum cost \(dp'[i][j][k][l]\) to obtain \(T_iT_{i+1}\ldots T_j\) from the first \(l\) letters of \(A_k\), that is, \(A_{k,1}\ldots A_{k,l}\) (or \(+\infty\) if impossible).

We loop over \(i\) for \(i=N,N-2,\ldots,1\) and \(j\) for \(j=i,i+1,\ldots,N\) in these orders, and find \(dp'[i][j][k][l]\) \((l>1)\) \(\to\) \(dp'[i][j][c], dp'[i][j][k][1]\) in this order.

Here, note that, when we compute \(dp'[i_0][j_0][k][l]\), we will have already obtained \(dp'[i_0][j][k][l]\) for all \(i_0\leq j\leq j_0-1\) and \(dp[i][j][c]\) for all \(i_0<i\leq j\leq N\). By definition of \(dp'[i][j][k][l]\), we can find the value as \(\displaystyle\min_{i_0\leq m\leq j_0-1} dp'[i_0][m][k][l-1]+dp[m+1][j_0][A_{k,l}]\). Here, we use the fact that, since \(|C_k|=1\) in each operation, it is uniquely determined how many trailing characters of \(T_iT_{i+1}\ldots T_j\) \(A_{k,l}\) was replaced to.

Next, we find \(dp[i][j][c]\) and \(dp'[i][j][k][1]\). \(dp[i][j][c]\) equals \(dp[i][j][c]=1\) if \(i=j\) and \(T_i=c\), or otherwise \(\displaystyle\min_{C_k=c} (dp'[i][j][k][|A_k|]+1)\) for \(k\) such that \(C_k=c\).

Since we already obtained those with \(|A_k|>1\), we can write this as \(dp[i][j][c]=(M[i][j][c], dp[i][j][d_{c,1}]+1, dp[i][j][d_{c,2}]+1,\ldots, dp[i][j][d_{c,k_c}]+1)\), where \(M[i][j][c]=\displaystyle\min_{C_k=c, |A_k|>1} (dp'[i][j][k][|A_k|]+1)\) and \(\{d_{c,k_m}\}\) is a set of \(A_k\) over \(k\) such that \(C_k=c\) and \(|A_k|=1\).

This part can be found by Dijkstra’s algorithm. Add an edge from a virtual vertex \(V\) to a vertex \(c\) with cost \(M[i][j][c]\). Plus, add an edge from vertex \(d_{c,m}\) to vertex \(c\) with cost \(1\). Then, \(d_{c,m}\) equals the minimum cost from vertex \(V\) to each vertex.

\(dp'[i][j][k][1]\) is found as \(dp'[i][j][k][1]=dp[i][j][A_{k,1}]\).

Now we can find the minimum cost of obtaining \(T\) from \(S\) in the same procedure as finding \(dp'[1][N][k][A_k]\). For example, we may define \(A_{k+1}=S\) and \(C_{k+1}=*\) (a character different from any alphabet letter) only when \(i=1\).

Now let us analyze the complexity. For each \(i\) and \(j\), we spend an \(O(KN\max(|A_i|))\) time to find \(dp'[i][j][k][l]\), and then spend an \(O((K+L)\log L)\) time (where \(C\) denotes the size of the alphabet). Thus, the total time complexity is \(O(N^3K\max(|A_i|)+N^2(K+L)\log L)\). Since \(N\leq 50\), \(K\leq 50\), \(\max(|A_i|)\leq 50\), and \(L\leq 26\), it is bounded by \(50^5\simeq 3\cdot 10^8\); in the actual computation, we have a constant factor of about \(\frac{1}{12}\sim\frac{1}{6}\) (depending on implementation), so it is fast enough. Therefore, the problem has been solved.

Note that, if the objective is achievable, then the number of operations is bounded by at most \((L-1)(1+2+\cdots +N)+(N-1)<32000\), so it is sufficient to use int type.

#include <bits/stdc++.h>
using namespace std;
#define N 51
#define INF (int)1e+9
#define rep(i, n) for(int i = 0; i < n; ++i)
#define rep2(i, a, b) for(int i = a; i <= b; ++i)
#define rep3(i, a, b) for(int i = a; i >= b; --i)
int main() {
	int n, m, k;
	string s, t;
	string c[N], a[N];
	int len[N];
	int dp1[N][N][26];
	int dp[N][N][N];
	vector<int>e[26];
	priority_queue<pair<int, int> >pq;
	pair<int, int>p;
	int sz[26];
	int x;
	cin >> s;
	cin >> t;
	cin >> k;
	rep(i, k) {
		cin >> c[i] >> a[i];
		len[i] = a[i].size();
		if (len[i] == 1)e[a[i][0] - 'a'].push_back(c[i][0] - 'a');
	}
	rep(i, 26)sz[i] = e[i].size();
	n = t.size();
	rep(i, n)rep2(j, i, n - 1)rep(ii, 26)dp1[i][j][ii] = INF;
	rep3(i, n - 1, 0) {
		rep2(j, i, n - 1)rep(ii, k)rep(jj, len[ii])dp[j][ii][jj] = INF;
		rep2(j, i, n - 1) {
			if (j == i) {
				dp1[i][j][t[j] - 'a'] = 0;
				pq.push({ 0,t[j] - 'a' });
			}
			else {
				rep(ii, k) {
					rep2(jj, 1, len[ii] - 1) {
						rep2(kk, i, j - 1) {
							if ((dp[kk][ii][jj - 1] < INF) && (dp1[kk + 1][j][a[ii][jj] - 'a'] < INF)) {
								dp[j][ii][jj] = min(dp[j][ii][jj], dp[kk][ii][jj - 1] + dp1[kk + 1][j][a[ii][jj] - 'a']);
							}
						}
					}
					if (dp[j][ii][len[ii] - 1] + 1 < dp1[i][j][c[ii][0] - 'a']) {
						dp1[i][j][c[ii][0] - 'a'] = dp[j][ii][len[ii] - 1] + 1;
						pq.push({ -dp1[i][j][c[ii][0] - 'a'],c[ii][0] - 'a' });
					}
				}
			}
			while (!pq.empty()) {
				p = pq.top();
				pq.pop();
				if (p.first == -dp1[i][j][p.second]) {
					x = p.second;
					rep(ii, sz[x]) {
						if (dp1[i][j][x] + 1 < dp1[i][j][e[x][ii]]) {
							dp1[i][j][e[x][ii]] = dp1[i][j][x] + 1;
							pq.push({ -dp1[i][j][e[x][ii]],e[x][ii] });
						}
					}
				}
			}
			rep(ii, k)dp[j][ii][0] = dp1[i][j][a[ii][0] - 'a'];
		}
	}
	m = s.size();
	rep(i, n + 1)rep(jj, m + 1)dp[i][k][jj] = INF;
	dp[0][k][0] = 0;
	rep(i, n) {
		rep(jj, m) {
			rep(j, i + 1) {
				dp[i + 1][k][jj + 1] = min(dp[i + 1][k][jj + 1], dp[j][k][jj] + dp1[j][i][s[jj] - 'a']);
			}
		}
	}
	if (dp[n][k][m] == INF)cout << -1 << endl;
	else cout << dp[n][k][m] << endl;
	return 0;
}

投稿日時:
最終更新: