题意:给你一个c串,你可以用任意小写字母替换c串中的 * 字符得到一个c',给你一个s和t串,定义:f(s1,s2) 为字符串 s2 在 s1 中出现的次数 ,求最大的 ans=f(c',s) - f(c',t)。
思路:首先预处理出 s 和 t 的next数组,然后,设dp【i】【j】【k】分别代表c串匹配到第 i 个字符,s串匹配到第 j 个字符,t串匹配到第 k 个字符的最大的答案,只能由前一个状态推出后面一个状态,如果当前状态没有值,那么就不能去推后一个状态,就continue,如果c【i】!= ’*‘ ,那么就直接kmp匹配,如果匹配到 s 串的最后一个字符,那么flag++,否则转移到下一个可以到达的状态,同理 t 串,t 串就flag - -。但是如果c【i】== ‘*’;就从 ‘ a ' 枚举到 ‘z ',然后kmp匹配再转移。
**:这题一定是拿已知当前状态去推导之后的状态。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1005,inf=1e9;
int d[maxn][55][55],next1[55],next2[55];
char c[maxn],s[55],t[55];
int n,m1,m2;
void init()
{
int len;
len=strlen(s);
next1[0]=-1;
for(int i=0,j=-1;i<len;)
{
if(j==-1||s[j]==s[i])next1[++i]=++j;
else j=next1[j];
}
len=strlen(t);
next2[0]=-1;
for(int i=0,j=-1;i<len;)
{
if(j==-1||t[i]==t[j])next2[++i]=++j;
else j=next2[j];
}
}
int get(int j,char str)
{
while(1)
{
if(j==-1||str==s[j])return j+1;
else j=next1[j];
}
}
int get1(int j,char str)
{
while(1)
{
if(j==-1||str==t[j])return j+1;
else j=next2[j];
}
}
int main()
{
scanf("%s%s%s",c+1,s,t);
init();
n=strlen(c + 1),m1=strlen(s),m2=strlen(t);
for(int i=0;i<=n;i++)
for(int j=0;j<m1;j++)
for(int k=0;k<m2;k++)
{
d[i][j][k]=-inf;
}
d[0][0][0]=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<m1;j++)
for(int k=0;k<m2;k++)
{
if(d[i][j][k]==-inf)continue;
if(c[i+1]!='*')
{
int flag = 0;
int j0=get(j,c[i+1]);
int k0=get1(k,c[i+1]);
if(j0==m1)
++flag,j0=next1[j0];
if(k0==m2)
--flag,k0=next2[k0];
d[i+1][j0][k0]=max(d[i+1][j0][k0],d[i][j][k]+flag);
}
else{
for(char y='a';y<='z';y++)
{
int flag = 0;
int j0=get(j,y);
int k0=get1(k,y);
if(j0==m1)
++flag,j0=next1[j0];
if(k0==m2)
--flag,k0=next2[k0];
d[i+1][j0][k0]=max(d[i+1][j0][k0],d[i][j][k]+flag);
}
}
}
}
int ans=-inf;
for(int i=0;i<m1;i++)
for(int j=0;j<m2;j++)
ans=max(ans,d[n][i][j]);
cout<<ans<<'\n';
}
来源:CSDN
作者:嘻嘻嘻西
链接:https://blog.csdn.net/weixin_44499508/article/details/103246088