用 AC自動機 來作有點想不到,撈一手就是學一手。ios
設 dp[ i ][ j ] 表示字符串 c 中的第 i 位到字典樹上節點 j 的最大值是多少, word[ j ] 表示在節點 j 下對答案修改的值是多少。c++
首先能夠肯定是 s 和 t 塞入字典樹時,他們的結尾節點的 word 值顯然一個是 1 一個是 -1 ,接下來就是 fail 數組上的一波操做,對於當前節點 j ,咱們的 word[ j ] 須要加上 word[ fail[ j ] ] ,即當選到當前節點 j 時候,加上可能匹配到的一個完整的 s 或者一個完整的 t 的影響。假設 s = "baaaa" , t = "aa" ,當 j 節點在 s 下的第一個 ‘a' 時, fail[ j ] 在 t 的第一個 ‘a’ , word[ j ] 不進行修改,當 j 節點在 s 下的第二個 'a' 時, fail[ j ] 在 t 的第二個 ‘a' , word[ j ] 更新值爲 word[ j ]-1 ,表示在匹配過程當中到 s 的 "baa" 時,剛好也匹配到了一個 t ,咱們須要減去一個完整的 t 帶來答案的影響,同理,到 s 的第三個 ‘a’ 不修改, s 的第四個 'a' 修改成 word[ j ]-1 ,那麼word就是這麼個做用。數組
接下來轉移方程就比較好理解了,設 id 爲在節點 j 下的 ‘a' ~ ‘z’ 的任意一個節點值,顯然只有在 c[ i ] 爲匹配符或者 c[ i ] 剛好等於節點 j 下對應的字符才能進行轉移,那麼轉移方程就是 dp[ i+1 ][ id ]=max(dp[ i+1 ][ id ],dp[ i ][ j ]+word[ id ]) ,最後只須要枚舉在全部節點下的 i 等於 c.size() 的 dp 值取 max 就是答案了。spa
1 // ——By DD_BOND 2 3 //#include<bits/stdc++.h> 4 #include<functional> 5 #include<algorithm> 6 #include<iostream> 7 #include<sstream> 8 #include<iomanip> 9 #include<climits> 10 #include<cstring> 11 #include<cstdlib> 12 #include<cstddef> 13 #include<cstdio> 14 #include<memory> 15 #include<vector> 16 #include<cctype> 17 #include<string> 18 #include<cmath> 19 #include<queue> 20 #include<deque> 21 #include<ctime> 22 #include<stack> 23 #include<map> 24 #include<set> 25 26 #define fi first 27 #define se second 28 #define MP make_pair 29 #define pb push_back 30 #define INF 0x3f3f3f3f 31 #define pi 3.1415926535898 32 #define lowbit(a) (a&(-a)) 33 #define lson l,(l+r)/2,rt<<1 34 #define rson (l+r)/2+1,r,rt<<1|1 35 #define Min(a,b,c) min(a,min(b,c)) 36 #define Max(a,b,c) max(a,max(b,c)) 37 #define debug(x) cerr<<#x<<"="<<x<<"\n"; 38 39 using namespace std; 40 41 typedef long long ll; 42 typedef pair<int,int> P; 43 typedef pair<ll,ll> Pll; 44 typedef unsigned long long ull; 45 46 const ll LLMAX=2e18; 47 const int MOD=1e9+7; 48 const double eps=1e-8; 49 const int MAXN=1e6+10; 50 51 inline ll sqr(ll x){ return x*x; } 52 inline int sqr(int x){ return x*x; } 53 inline double sqr(double x){ return x*x; } 54 ll gcd(ll a,ll b){ return b==0? a: gcd(b,a%b); } 55 ll exgcd(ll a,ll b,ll &x,ll &y){ ll d; (b==0? (x=1,y=0,d=a): (d=exgcd(b,a%b,y,x),y-=a/b*x)); return d; } 56 ll qpow(ll a,ll n){ll sum=1;while(n){if(n&1)sum=sum*a%MOD;a=a*a%MOD;n>>=1;}return sum;} 57 inline int dcmp(double x){ if(fabs(x)<eps) return 0; return (x>0? 1: -1); } 58 59 int tree[110][26],word[110],fail[110],cnt=0,dp[1010][110]; 60 61 void insert(string s,int v){ 62 int root=0; 63 for(int i=0;i<(int)s.size();i++){ 64 int id=s[i]-'a'; 65 if(!tree[root][id]) tree[root][id]=++cnt; 66 root=tree[root][id]; 67 } 68 word[root]+=v; 69 } 70 71 void get_fail(){ 72 queue<int>q; 73 for(int i=0;i<26;i++) 74 if(tree[0][i]){ 75 fail[tree[0][i]]=0; 76 q.push(tree[0][i]); 77 } 78 while(!q.empty()){ 79 int u=q.front(); q.pop(); 80 for(int i=0;i<26;i++) 81 if(tree[u][i]){ 82 fail[tree[u][i]]=tree[fail[u]][i]; 83 q.push(tree[u][i]); 84 } 85 else tree[u][i]=tree[fail[u]][i]; 86 word[u]+=word[fail[u]]; 87 } 88 } 89 90 int main(void) 91 { 92 ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); 93 int ans=-INF; string c,s,t; cin>>c>>s>>t; 94 insert(s,1); insert(t,-1); get_fail(); 95 memset(dp,-INF,sizeof(dp)); 96 dp[0][0]=0; 97 for(int i=0;i<(int)c.size();i++) 98 for(int j=0;j<=cnt;j++) 99 for(int z=0;z<26;z++) 100 if(c[i]=='*'||'a'+z==c[i]){ 101 int id=tree[j][z]; 102 dp[i+1][id]=max(dp[i+1][id],dp[i][j]+word[id]); 103 } 104 for(int i=0;i<=cnt;i++) ans=max(ans,dp[c.size()][i]); 105 cout<<ans<<endl; 106 return 0; 107 }