cf 1337E - Kaavi and Magic Spell (区间DP)
题目:传送门
题意:给出两个字符串S和T, 和一个空字符串A, 每次将s的第一个字符放在A的前面或后面 ;求 A串 在这样的过程中 ,其前缀等于T的方法数 (若S=T=“a” , 字符‘a’可以往空串前插也可以后插,故是两种方法)
设 dp(i,l,r) 表示 S串中的前i个字符 形成的字符串与 T串中的 [ l , r ] 完全匹配的方法数 ,由于 i 个字符形成的字符串长度为 i ,所以一定有 r-l+1 == i 。因此,dp(i,l,r) 可以简化为 dp(l,r) ;
前缀等于T的A串 , 可以表示为 A = T + "??...?"('?'可以与任意字母匹配) ,A串长度为n 、 T串长度为m; 上述的与T串匹配 可以看做: 前i个字符形成的字符串 与 满足题意的A串匹配
1. 若 s[i] == t[l] , 则有 dp(l,r) = dp(l,r) + dp(l+1,r) , 前插 s[i] 【 s[i] 与 t[l] 匹配 ;状态转移:前 i-1 个字符形成的字符串 ( i-1 == r-(l+1)+1 ) 与 t[ l+1 , r ] 的完全匹配 + 前插 s[i] ==》 前 i=r-l+1 个字符形成的字符串与t[ l , r ] 的完全匹配 】
2. 若 s[i] == t[r] , 则有 dp(l,r) = dp(l,r) + dp(l,r-1) , 后插 s[i]
3. 若 l > m || r > m , 则有 dp(l,r) = dp(l,r) + dp(l,r-1) + dp(l+1,r) 【这里的 > m 指的是 与在A串中的“任意串”进行匹配, 既然是 “任意串” 那么前插后插都满足】
AC代码:(dp的预处理见代码注释)
1 #include<bits/stdc++.h> 2 #pragma GCC optimize(2) 3 using namespace std; 4 typedef long long LL; 5 typedef pair<int,int> pii; 6 typedef pair<double,double> pdd; 7 const int N=3e3+5; 8 const LL inf=(1uLL<<63)-1; 9 const LL mod=998244353; 10 const double eps=1e-9; 11 const long double pi=acos(-1.0L); 12 #define ls (i<<1) 13 #define rs (i<<1|1) 14 #define fi first 15 #define se second 16 #define pb push_back 17 #define mk make_pair 18 #define mem(a,b) memset(a,b,sizeof(a)) 19 LL read() 20 { 21 LL x=0,t=1; 22 char ch; 23 while(!isdigit(ch=getchar())) if(ch=='-') t=-1; 24 while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); } 25 return x*t; 26 } 27 char s[N],t[N]; 28 LL dp[N][N]; 29 int main() 30 { 31 scanf("%s%s",s+1,t+1); 32 int n=strlen(s+1),m=strlen(t+1); 33 for(int i=1;i<=n+1;i++) dp[i][i-1]=1;//dp[i][i]=dp[i][i-1]+dp[i+1][i]=2 (i,i-1)可以视为空串 34 for(int i=1;i<=n;i++) 35 { 36 for(int l=1,r=i;r<=n;l++,r++) 37 { 38 if(l>m||s[i]==t[l]) dp[l][r]+=dp[l+1][r],dp[l][r]%=mod; 39 if(r>m||s[i]==t[r]) dp[l][r]+=dp[l][r-1],dp[l][r]%=mod; 40 } 41 } 42 LL ans=0; 43 for(int i=m;i<=n;i++) ans+=dp[1][i],ans%=mod; 44 printf("%lld\n",ans); 45 return 0; 46 }