CF1336C(挺重要的区间dp)

Kaavi and Magic Spell - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

我们直接考虑如何构造出来的字符串,这个字符串显然只能每次最左端加或者最右端加入。

对于第一个字符,显然每个位置都够能放置,且有两种方案。接着下一个字符加入它的左端或者右端,依次类推。

令 dp[i][j] 为 s(1)~s(j-i+1) 构造出 t(i)~t(j)的方案数。

(这种思想跟合唱队是同一种区间dp思想,P3205 [HNOI2010]合唱队(区间dp+方案数) - QAQ啥也不会 - 博客园 (cnblogs.com))

 

对于dp[i][j]的转移方程:

当前s[j-i+1]加入最左边,且s[j-i+1]==t[i]:dp[i][j]=(dp[i][j]+dp[i+1][j])%MOD;

当前s[j-i+1]加入最右边,且s[j-i+1]==t[j]:dp[i][j]=(dp[i][j]+dp[i][j-1])%MOD;

 

当然显然本题 t 字符串的长度可能会短,所以 s[j-i+1] 加入的位置大于了 t 字符串的长度,显然此时一定是合法的状态

所以dp[i][j]的转移方程便是:

当前s[j-i+1]加入最左边,且s[j-i+1]==t[i] or i>tlen :dp[i][j]=(dp[i][j]+dp[i+1][j])%MOD;

当前s[j-i+1]加入最右边,且s[j-i+1]==t[j] or j>tlen :dp[i][j]=(dp[i][j]+dp[i][j-1])%MOD;

 

对于dp初始化:

for(int i=1;i<=m;i++) dp[i][i]=2*(s[1]==t[i]);

for(int i=m+1;i<=n;i++) dp[i][i]=2;

 

最后答案的统计:由于本题构造出来的字符串合法即可,所有最后的答案不是 dp[1][n],而是所有合法的dp[i][j] ,即Σdp[i][j] ( m≤j≤n )

CODE:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define db long double
#define mp make_pair
#define pb push_back   
#define popb pop_back  
#define fi first
#define se second
#define popcount __builtin_popcount
#define popcountll __builtin_popcountll
const int N=3010;
//const int M=;
//const int inf=(int)1e9;
//const ll INF=(ll)1e18;
const ll MOD=998244353;
int T,n;
ll dp[N][N];
char s[N],t[N];
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int main()
{
//    freopen("","r",stdin);
//    freopen("","w",stdout);
//    ios::sync_with_stdio(0);
//    cin.tie(0);
    scanf("%s",s+1);scanf("%s",t+1);
    int n=strlen(s+1),m=strlen(t+1);
    for(int i=1;i<=m;i++) dp[i][i]=2*(s[1]==t[i]);
    for(int i=m+1;i<=n;i++) dp[i][i]=2;
    for(int len=2;len<=n;len++)
        for(int i=1;i+len-1<=n;i++)
        {
            int j=i+len-1; // dp[i][j]
            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;
        }
    ll ans=0;
    for(int i=m;i<=n;i++) ans=(ans+dp[1][i])%MOD;
//    for(int i=1;i<=n;i++)
//        for(int j=1;j<=n;j++)
//            printf("%d %d %d\n",i,j,dp[i][j]);
    printf("%lld\n",ans);
    return 0;
}

 

 



 

 

posted @ 2023-07-13 21:19  QAQ啥也不会  阅读(12)  评论(0编辑  收藏  举报