区间 dp
CF1336C Kaavi and Magic Spell
- \(S\) 串两端添加具有区间 dp 的特征。
- \(S \to T\) 的构建一定是从短到长的,考虑区间 dp。
- 设 \(dp_{i, j}\) 表示构建出 \(T : [i, j]\) 的方案数。
- 答案:\(\displaystyle \sum_{i = m} ^ n dp_{1, i}\)。
- 转移:
\[dp_{i, j} = dp_{i, j} + dp_{i + 1, j} \ (s_{j - i + 1} = t_i \lor i > m)
\]
\[dp_{i, j} = dp_{i, j} + dp_{i, j - 1} \ (s_{j - i + 1} = t_j \lor j > m)
\]
- 初始状态:\(dp_{i, i} = 2 \times [i > m \lor s_1 = t_i]\)。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e3 + 5;
const int mod = 998244353;
int n, m, dp[N][N];
string s, t;
signed main() {
ios_base :: sync_with_stdio(NULL);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> s >> t;
n = s.size(), m = t.size();
s = " " + s, t = " " + t;
for(int i = 1 ; i <= n ; ++ i)
dp[i][i] = 2 * (i > m || s[1] == t[i]);
for(int len = 2 ; len <= n ; ++ len)
for(int i = 1 ; i + len - 1 <= n ; ++ i) {
int j = i + len - 1;
if(i > m || s[len] == t[i]) dp[i][j] = (dp[i][j] + dp[i + 1][j]) % mod;
if(j > m || s[len] == t[j]) dp[i][j] = (dp[i][j] + dp[i][j - 1]) % mod;
}
int ans = 0;
for(int i = m ; i <= n ; ++ i)
ans = (ans + dp[1][i]) % mod;
cout << ans;
return 0;
}
P2470 [SCOI2007] 压缩
- \(dp_{i, j}\) 的信息不够,因为 \(R\) 关心上一个 \(M\) 在哪里(可以是 \(0\))。
- 设 \(dp_{i, j, 0 / 1}\) 表示将区间 \([i, j]\) 的字符压缩且之前是否有 \(M\)。
- 答案:\(\min \{ dp_{1, n, 0}, dp_{1, n, 1} \}\)。
- 转移:
- \(j\) 后面加 \(R\):
\[dp_{i, j, 0} = \min \{ dp_{i, j, 0}, dp_{i, mid, 0} + 1 \} \ (s_{[i, mid]} = s_{[mid + 1, j]})
\]
- \(j\) 后面不加 \(R\):
\[dp_{i, j, 0} = \min_{k \in [i, j]} \{ dp_{i, j, 0}, dp_{i, k, 0} + j - k \}
\]
- \(j\) 后面加 \(M\):
\[dp_{i, j, 1} = \min_{k \in [i, j)} \{ dp_{i, j, 1}, \min \{ dp_{i, k, 1}, dp_{i, k, 0} \} + \min \{ dp_{k + 1, j, 0}, dp_{k + 1, j, 1} \} + 1 \}
\]
- \(j\) 后面不加 \(M\):
\[dp_{i, j, 1} = \min_{k \in [i, j)} \{ dp_{i, j, 1}, dp_{i, k, 1} + dp_{k + 1, j, 0} \}
\]
- 初始状态:\(dp_{i, i, 0} = 1, dp_{i, i, 1} = 2\)。