习题:Kaavi and Magic Spell(dp)

题目

传送门

思路

这题的dp设计状态确实不好想,并且难点也在dp设计状态上,而不是在状态转移上

\(dp[i][j]\)表示S的前\(j-i+1\)个字符会构成T中的\(i到j\)的字符串

因为一个字符只能接在原来序列的前或者后

我们考虑新加入一个字符\(s[j-i+1]\),如果其为T的\(t[j]\),即是后面开始匹配

\(dp[i][j]=dp[i][j]+dp[i][j-1]\)

如果其为T的\(t[i]\),即使从前面开始匹配

\(dp[i][j]=dp[i][j]+dp[i+1][j]\)

之后考虑初始状态,即一个字符的匹配,但是注意,我们这里注意的是操作的数量,

对于一个\(s[1]=t[i]\)\(dp[i][i]\)的值应当为\(2\),而不是\(1\)

之后我们还有剩下的\(lens-lent\)个字符,对于这一块的处理方案,

我们考虑在\(t\)后面填充一种特殊字符使其能和任意字符都能匹配

最终的答案即为\(\sum_{i=lent}^{lens}dp[1][i]\)

代码

#include<iostream>
#include<cstring>
using namespace std;
const int mod=998244353;
char a[3005],b[3005];
int lena,lenb;
long long ans,dp[3005][3005];
//用S的前j-i+1个字符拼出t中的i~j的字符
int main()
{
    ios::sync_with_stdio(false);
    cin>>(a+1)>>(b+1);
    lena=strlen(a+1);
    lenb=strlen(b+1);
    for(int i=1;i<=lena;i++)
        if(a[1]==b[i]||i>lenb)
            dp[i][i]=2;
    for(int len=2;len<=max(lena,lenb);len++)
    {
        for(int l=1;l+len-1<=lena;l++)
        {
            int r=l+len-1;
            if(a[len]==b[l]||l>lenb)
                dp[l][r]=(dp[l][r]+dp[l+1][r])%mod;
            if(a[len]==b[r]||r>lenb)
                dp[l][r]=(dp[l][r]+dp[l][r-1])%mod;
        }
    }
    for(int i=lenb;i<=lena;i++)
        ans=(ans+dp[1][i])%mod;
    cout<<ans;
    return 0;
}
posted @ 2020-07-28 14:44  loney_s  阅读(99)  评论(0)    收藏  举报