Codeforces Round #558 (Div. 2) D kmp + dp

怎甘沉沦 提交于 2019-11-30 03:23:05

 题目链接

题意:给你一个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';
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!