【KMP+DP】Codeforces - 1163 - D.Mysterious Code

题目链接http://codeforces.com/problemset/problem/1163/D


题意:

给出一个字符串s由小写字母和星号组成,字符串a和b仅由小写字母组成。
星号可变成任意一个字符,问字符串a在s中出现的次数与b出现的次数之差最大是多少。


题解:

d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示第i位,匹配了字符串a j位,字符串b k位的答案。
利用KMP的next数组更新。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+7;
void getnex(char s[N],int nex[N],int n){
    int i=0,j=-1;
    nex[0]=-1;
    while(i<n){
        if(j==-1||s[i]==s[j]) i++,j++,nex[i]=j;
        else j=nex[j];
    }
}

int dp[N][60][60];
char s[N],a[N],b[N];
int na[N],nb[N];

int main(){
    scanf("%s%s%s",s,a,b);
    int sn=strlen(s),sa=strlen(a),sb=strlen(b);
    getnex(a,na,sa);
    getnex(b,nb,sb);
    memset(dp,-125,sizeof(dp));
    dp[0][0][0]=0;
    for(int i=1;i<=sn;i++){
        if(s[i-1]=='*'){
            for(int j=0;j<=sa;j++){
                for(int k=0;k<=sb;k++){
                    for(char c='a';c<='z';c++){
                        int dj=j,dk=k;
                        while(c!=a[dj]&&dj!=-1) dj=na[dj];
                        while(c!=b[dk]&&dk!=-1) dk=nb[dk];
                        dj++;dk++;
                        int tmp=dp[i-1][j][k];
                        if(dj==sa) tmp++;
                        if(dk==sb) tmp--;
                        dp[i][dj][dk]=max(dp[i][dj][dk],tmp);
                    }
                }
            }
        }
        else{
            for(int j=0;j<=sa;j++){
                for(int k=0;k<=sb;k++){
                    char c=s[i-1];
                    int dj=j,dk=k;
                    while(c!=a[dj]&&dj!=-1) dj=na[dj];
                    while(c!=b[dk]&&dk!=-1) dk=nb[dk];
                    dj++;dk++;
                    int tmp=dp[i-1][j][k];
                    if(dj==sa) tmp++;
                    if(dk==sb) tmp--;
                    dp[i][dj][dk]=max(dp[i][dj][dk],tmp);
                }
            }
        }
    }
    int ans=-(int)1e9;
    for(int i=0;i<=sa;i++){
        for(int j=0;j<=sb;j++){
            ans=max(ans,dp[sn][i][j]);
        }
    }
    printf("%d\n",ans);
}
/*
abc
abc
zzz
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值