将两个串插入AC自动机,AC自动机带点权,S串带权值1,T串带权值-1,对树在构建时求树上点权前缀和,然后设表示到的第个字符,在ACA上的第个节点时的答案,那么就有转移方程:
#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, M = 26, MOD = 1e9 + 7;
#define mp(x) (x -'a')
namespace ACA{
int ch[N][M], fail[N], ed[N], val[N];
int sz;
void init() {
sz = 1;
memset(ch[0], 0, sizeof(ch));
}
void insert(const string &s, int id, int v) {
int n = s.size(), u = 0, c;
for(int i = 0; i < n; i++) {
c = mp(s[i]);
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
ch[u][c] = sz++;
}
u = ch[u][c];
}
ed[u] = id, val[u] += v;
}
void build() {
queue<int> Q;
fail[0] = 0;
for(int c = 0, u; c < M; c++) {
u = ch[0][c];
if(u) { Q.emplace(u); fail[u] = 0; }
}
while(!Q.empty()) {
int r = Q.front(); Q.pop();
for(int c = 0, u; c < M; c++) {
u = ch[r][c];
if(!u) {
ch[r][c] = ch[fail[r]][c];
continue;
}
fail[u] = ch[fail[r]][c];
Q.emplace(u);
}
val[r] += val[fail[r]];
}
}
}
using ACA::val;
int dp[1010][110];
inline void solve(){
string c, s, t; cin >> c >> s >> t;
ACA::init();
ACA::insert(s, 0, 1), ACA::insert(t, 0, -1), ACA::build();
memset(dp, -0x3f, sizeof(dp));
dp[0][0] = 0;
for(int i = 0; i < c.size(); i++) {
for(int j = 0; j <= ACA::sz; j++) {
for(int k = 0; k < 26; k++) {
if(c[i] == '*' || c[i] - 'a' == k) {
int id = ACA::ch[j][k];
dp[i + 1][id] = max(dp[i + 1][id], dp[i][j] + val[id]);
}
}
}
}
int ans = -1e9;
for(int i = 0; i <= ACA::sz; i++) ans = max(ans, dp[c.size()][i]);
cout << ans << endl;
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
cout << fixed << setprecision(12);
int t = 1; // cin >> t;
while(t--) solve();
return 0;
}