本题观察数据量非常小,并且求的是多串匹配,因此可以考虑使用ac自动机
设计dp状态为f[][],表示c中前i个字符匹配到第j个节点所能达到的最大值。
首先我们知道,两个匹配串在结束位置的点分别是+-1,而所有前缀能包含这两个字符串的,也应该设为对应的数值,对fail树进行修改进行。
dp的时候,枚举位置,枚举之前处于的节点位置,当前位置是什么字符,进行dp即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+10; struct node{ int cnt; node * nxt[27]; node * fail; vector<node *> num; }*rt; node pool[N]; int n,idx; int val[N]; int num; int f[1100][200]; void insert(string s,int x){ node *p=rt; int i; for(i=0;i<s.size();i++){ int sign=s[i]-'a'; if(p->nxt[sign]==NULL){ p->nxt[sign]=pool+(++idx); p->nxt[sign]->cnt=++num; } p=p->nxt[sign]; if(i==(int)s.size()-1){ val[p->cnt]=x; } } } void build(){ int i; queue<node *> q; rt->fail=rt; for(i=0;i<26;i++){ if(rt->nxt[i]){ rt->nxt[i]->fail=rt; rt->num.push_back(rt->nxt[i]); q.push(rt->nxt[i]); } else{ rt->nxt[i]=rt; rt->nxt[i]->fail=rt; } } while(q.size()){ auto t=q.front(); q.pop(); for(i=0;i<26;i++){ if(t->nxt[i]){ t->nxt[i]->fail=t->fail->nxt[i]; t->fail->nxt[i]->num.push_back(t->nxt[i]); q.push(t->nxt[i]); } else{ t->nxt[i]=t->fail->nxt[i]; } } val[t->cnt]+=val[t->fail->cnt]; } } int main(){ ios::sync_with_stdio(false); int i; rt=pool; rt->cnt=0; string c; cin>>c; n=c.size(); c=" "+c; string s,t; cin>>s>>t; insert(s,1); insert(t,-1); build(); memset(f,-0x3f,sizeof f); f[0][0]=0; for(i=1;i<=n;i++){ for(int j=0;j<=num;j++){ for(int k=0;k<26;k++){ if(c[i]=='*'||(c[i]=='a'+k)){ int id=(pool+j)->nxt[k]->cnt; f[i][id]=max(f[i][id],f[i-1][j]+val[id]); } } } } int ans=-0x3f3f3f3f; for(i=0;i<=num;i++) ans=max(ans,f[n][i]); cout<<ans<<endl; }