肥宅快乐串-动态规划

题目:

对于两个字符串的两个公共子序列 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]);
    }
}
posted @ 2019-07-15 20:57  booiris  阅读(195)  评论(0编辑  收藏  举报