区间 dp

CF1336C Kaavi and Magic Spell

  1. \(S\) 串两端添加具有区间 dp 的特征。
  2. \(S \to T\) 的构建一定是从短到长的,考虑区间 dp。
  3. \(dp_{i, j}\) 表示构建出 \(T : [i, j]\) 的方案数。
  4. 答案:\(\displaystyle \sum_{i = m} ^ n dp_{1, i}\)
  5. 转移:

\[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) \]

  1. 初始状态:\(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] 压缩

  1. \(dp_{i, j}\) 的信息不够,因为 \(R\) 关心上一个 \(M\) 在哪里(可以是 \(0\))。
  2. \(dp_{i, j, 0 / 1}\) 表示将区间 \([i, j]\) 的字符压缩且之前是否有 \(M\)
  3. 答案:\(\min \{ dp_{1, n, 0}, dp_{1, n, 1} \}\)
  4. 转移:
  • \(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} \} \]

  1. 初始状态:\(dp_{i, i, 0} = 1, dp_{i, i, 1} = 2\)
posted @ 2025-08-06 21:56  endswitch  阅读(4)  评论(0)    收藏  举报