Codeforces 1337 E. Kaavi and Magic Spell(区间dp)

题目链接
题目大意:
给定一个字符串S和T。有两种操作:
1.将S的最前面的字符移到A字符串的最前面,然后将S中的这个最前面的字符删掉。
2.将S的最前面的字符移到A字符串的最后面,然后将S中的这个最前面的字符删掉。
用不超过n个操作,问有多少个操作序列能够使得生成的字符串的前缀为T。

解题思路:
区间dp。首先将T想象成S一样长的字符,其中长度大于T的部分就是对任何字符都可以匹配。
dp[i][j]表示T中[i…j]被匹配的方案数。
然后最外层枚举区间长度len,内层枚举i。
将S的第len个字符插入T的最前面,则将S[len]和T[i]进行比较,如果相同则 dp[i][i+len-1]+ = dp[i+1][i+len-1]。
将S的第len个字符插入T的最后面,则将S[len]和T[i+len-1]进行比较,如果相同则dp[i][i+len-1]+=dp[i][i+len-2]。
因为操作不超过n次,但为了有T的前缀,最少要操作m次,则将dp[1][m…n]的答案都加起来,最后*2就是答案了。

解题代码:

#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=2e5+10;
ll dp[3001][3001];
ll mod=998244353;
int n,m;
char s1[3005],s2[3005];
bool cmp(int i,int j)
{
    if(j>m)
    return true;
    return s1[i]==s2[j];
}
int main()
{
    cin>>s1+1>>s2+1;
    n=strlen(s1+1);
    m=strlen(s2+1);
    for (int i=1;i<=n;i++)
    {
        if (cmp(1,i))
        dp[i][i]=1;
    }
    for (int len=2;len<=n;len++)
    {
        for (int i=1;i+len-1<=n;i++)
        {
            if (cmp(len,i))
                dp[i][i+len-1]=(dp[i][i+len-1]+dp[i+1][i+len-1])%mod;
            if (cmp(len,i+len-1))
            	dp[i][i+len-1]=(dp[i][i+len-1]+dp[i][i+len-2])%mod;
        }
	}
    ll ans=0;
    for (int i=m;i<=n;i++)
    ans=(ans+dp[1][i])%mod;
    cout<<(ans*2ll)%mod;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值