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 或者一个完整的的影响。假设 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 }

 

posted @ 2019-05-11 01:07  DD_BOND  阅读(846)  评论(0编辑  收藏  举报