Codeforces 1163D Mysterious Code (kmp + dp)

D. Mysterious Code

time limit per test:2 seconds

memory limit per test:256 megabytes

During a normal walk in the forest, Katie has stumbled upon a mysterious code! However, the mysterious code had some characters unreadable. She has written down this code as a string c consisting of lowercase English characters and asterisks ("*"), where each of the asterisks denotes an unreadable character. Excited with her discovery, Katie has decided to recover the unreadable characters by replacing each asterisk with arbitrary lowercase English letter (different asterisks might be replaced with different letters).

Katie has a favorite string s and a not-so-favorite string t and she would love to recover the mysterious code so that it has as many occurrences of s as possible and as little occurrences of t as possible. Formally, let's denote f(x,y) as the number of occurrences of y in x (for example, f(aababa,ab)=2). Katie wants to recover the code c′ conforming to the original c, such that f(c′,s)−f(c′,t) is largest possible. However, Katie is not very good at recovering codes in general, so she would like you to help her out.

Input
The first line contains string c (1≤|c|≤1000) — the mysterious code . It is guaranteed that c consists of lowercase English characters and asterisks "*" only.

The second and third line contain strings s and t respectively (1≤|s|,|t|≤50, s≠t). It is guaranteed that s and t consist of lowercase English characters only.

Output
Print a single integer — the largest possible value of f(c′,s)−f(c′,t) of the recovered code.

Examples

input

*****
katie
shiro

output

1

input

caat
caat
a

output

-1

input

*a*
bba
b

output

0

input

***
cc
z

output

2

Note

Note
In the first example, for c′ equal to "katie" f(c′,s)=1 and f(c′,t)=0, which makes f(c′,s)−f(c′,t)=1 which is the largest possible.

In the second example, the only c′ conforming to the given c is "caat". The corresponding f(c′,s)−f(c′,t)=1−2=−1.

In the third example, there are multiple ways to recover the code such that f(c′,s)−f(c′,t) is largest possible, for example "aaa", "aac", or even "zaz". The value of f(c′,s)−f(c′,t)=0 for all of these recovered codes.

In the fourth example, the optimal recovered code c′ would be "ccc". The corresponding f(c′,s)−f(c′,t)=2.

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

题目大意:给一个字符换c,'*'可以替换为任意字符,设f(x, y)表示x串中包含y子串的个数,求max(f(c,s)-f(c,t))

题目分析:dp[i][j][k]表示c匹配到i位置,s匹配到j位置,t匹配到k位置时的答案,转移方程为

dp[i][j][k] = (ch from 'a' to 'z') max(dp[i-1][prej][prek] + (j == lens - k == lent))

考虑c[i] = '*'的情况,需要枚举26个字母,prej到j的转移表示字符串s在prej的位置时加上一个字符ch后匹配位置变成j,prek到k同理,这个转移关系正好对应kmp的next数组,可以预处理出来,总的时间复杂度O(26|c||s||t|)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int const INF = 0x3fffffff;
int const MAXN = 1005;
int const MAXM = 55;
char c[MAXN], s[MAXM], t[MAXM];
int lenc, lens, lent;
int nxt[MAXM], ns[MAXM][26], nt[MAXM][26], dp[MAXN][MAXM][MAXM];

void prepare(char* str, int len, int res[MAXM][26]) {
    memset(nxt, 0, sizeof(nxt));
    int j = 0;
    nxt[1] = 0;
    for (int i = 2; i <= len; i++) {
        while (j && str[j + 1] != str[i]) {
            j = nxt[j];
        }
        if (str[j + 1] == str[i]) {
            j++;
        }
        nxt[i] = j;
    }
    for (int i = 0; i <= len; i++) {
        for (char ch = 'a'; ch <= 'z'; ch++) {
            int cur = i;
            while (cur && str[cur + 1] != ch) {
                cur = nxt[cur];
            }
            if (str[cur + 1] == ch) {
                cur++;
            }
            res[i][ch - 'a'] = cur;
        }
    }
}

int main() {
    scanf("%s %s %s", c + 1, s + 1, t + 1);
    lenc = strlen(c + 1);
    lens = strlen(s + 1);
    lent = strlen(t + 1);
    prepare(s, lens, ns);
    prepare(t, lent, nt);
    for (int i = 0; i <= lenc; i++) {
        for (int j = 0; j <= lens; j++) {
            for (int k = 0; k <= lent; k++) {
                dp[i][j][k] = -INF;
            }
        }
    }
    dp[0][0][0] = 0;
    for (int i = 1; i <= lenc; i++) {
        for (int j = 0; j <= lens; j++) {
            for (int k = 0; k <= lent; k++) {
                for (char ch = 'a'; ch <= 'z'; ch++) {
                    if (c[i] == '*' || c[i] == ch) {
                        int nxtspos = ns[j][ch - 'a'];
                        int nxttpos = nt[k][ch - 'a'];
                        int val = (nxtspos == lens) - (nxttpos == lent);
                        dp[i][nxtspos][nxttpos] = max(dp[i][nxtspos][nxttpos], dp[i - 1][j][k] + val);
                    }
                }
            }
        }
    }
    int ans = -INF;
    for (int j = 0; j <= lens; j++) {
        for (int k = 0; k <= lent; k++) {
            ans = max(ans, dp[lenc][j][k]);
        }
    }
    printf("%d\n", ans);
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值