Codeforces 1163D Mysterious Code(AC自动机+DP)

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 或者一个完整的的影响。假设 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 }
相关文章
相关标签/搜索