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 }
相關文章
相關標籤/搜索