肥宅快乐串-动态规划
题目:
对于两个字符串的两个公共子序列 s1 与 s2 ,设 s1 中的字符在第一个字符串中出现的位置(下标)集合为 P11 ,在第二个字符串中出现的位置集合为 P12 ;设 s2 中的字符在第一个字符串中出现的位置集合为 P21 ,在第二个字符串中出现的位置集合为 P22 。则 zy 认为 s1==s2 当且仅当p11=p21且p12=p22。
现在请你编写程序计算一下,当 zy 两个给定的字符串时,他共有可能实际看到多少种不同的公共子序列。由于答案可能很大,你只需要输出准确答案对 998244353 的余数即可。
思路:
题意就是给出两个字符串,找出他们的公共子序列个数,对于aa和a,有两个不同公共子序列,因为他们的位置不同。
F(i,j)为字符串1的第i个字符前缀,和字符串2的第j个字符前缀的公共子序列数:
所以递推公式为:
\[dp(i,j)=\begin{cases}
dp(i-1,j)+dp(i,j-1)-dp(i-1,j-1) (s1[i]!=s2[j])\\
dp(i-1,j)+dp(i,j-1)+1 (s1[i]==s2[j])\\
\end{cases}
\]
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
#define INF 0x3f3f3f3f
using namespace std;
const int mod = 998244353;
int n, m;
char s1[1005], s2[1005];
long long dp[1005][1005];
void solve()
{
memset(dp, 0, sizeof dp);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if(s1[i-1]==s2[j-1])
dp[i][j] = (dp[i - 1][j] + dp[i][j - 1] + 1) % mod;
else
dp[i][j] = (dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + mod) % mod;
}
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
scanf("%s%s", s1, s2);
solve();
printf("%lld\n", dp[n][m]);
}
}