Codeforces 1163D Mysterious Code(AC自动机+DP)
用 AC自动机 来做有点想不到,捞一手就是学一手。
设 dp[ i ][ j ] 表示字符串 c 中的第 i 位到字典树上节点 j 的最大值是多少, word[ j ] 表示在节点 j 下对答案修改的值是多少。
首先可以确定是 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 就是答案了。
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 }